Objecitve C/Swift 捏合放大区域

Objecitve C/Swift Pinch to Zoom into area

提问人:user1513171 提问时间:12/15/2020 最后编辑:Willekeuser1513171 更新时间:12/18/2020 访问量:140

问:

我发现了很多关于 SO 的捏合缩放问题,并且我已经能够遵循它们来实际让它工作,但我遇到的问题是它的工作原理。

当我捏合缩放时,我以为它会放大到我捏合时手指所在的区域。但是,无论我的手指位于何处,当我捏合时,它都会放大到恰好是我视图左上角的同一区域。有没有办法控制缩放发生的位置?

作为参考,我正在实现我的捏合以使用滚动视图进行缩放,如下所示(在目标 C 中,但答案可以在 Swift 中):

 _scrollView = [[UIScrollView alloc] init];// scrollview
 _nestedView = [[UIView alloc] init];// top level view within scrollview that contains everything
 _scrolledView = scrolledView;// the view I want to zoom into when pinching - a UIView in this case

// viewDidLoad
 self.scrollView.translatesAutoresizingMaskIntoConstraints = NO;
  self.nestedView.translatesAutoresizingMaskIntoConstraints = NO;
  [self.scrollView addSubview:self.nestedView];
 
  [self.view addSubview:self.scrollView];
  
  self.scrollView.delegate = self;
  self.scrollView.panGestureRecognizer.enabled = YES;// tried with this on an off but doesn't seem to do anything
  self.scrollView.bouncesZoom = NO;
  self.scrollView.minimumZoomScale = 1.0;
  self.scrollView.maximumZoomScale = 3.0;
  self.scrollView.zoomScale = 1.0;

// Delegate
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
  return self.scrolledView;
}

// Constraints
 [NSLayoutConstraint constraintWithItem:self.nestedView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0],
      [NSLayoutConstraint constraintWithItem:self.nestedView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0],
      [NSLayoutConstraint constraintWithItem:self.nestedView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0.0],
      [NSLayoutConstraint constraintWithItem:self.nestedView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0],
                                            
                                            
      [NSLayoutConstraint constraintWithItem:self.scrollView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0],
      [NSLayoutConstraint constraintWithItem:self.scrollView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0],
      [NSLayoutConstraint constraintWithItem:self.scrollView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0.0],
      [NSLayoutConstraint constraintWithItem:self.scrollView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0],


// scrolledView constraints
 [NSLayoutConstraint constraintWithItem:self.scrolledView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0],
    [NSLayoutConstraint constraintWithItem:self.scrolledView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0],
    [NSLayoutConstraint constraintWithItem:self.scrolledView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0.0],
    [NSLayoutConstraint constraintWithItem:self.scrolledView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0],

所以再一次,捏缩放发生了,但它只是不断放大到我的视图(scrolledView)的左上角,不幸的是,这使得缩放对我的用例完全没有意义。

Objective-C Swift UIscrollView 捏缩放

评论

0赞 skaak 12/15/2020
您还需要设置滚动视图的内容偏移量。
0赞 user1513171 12/15/2020
@skaak 我什么时候需要设置?当捏手势正在完成时?我怎么知道要设置它?
0赞 skaak 12/15/2020
等等,从手册中您可以获得以下内容。若要使缩放和平移正常工作,委托必须同时实现 viewForZoomingInScrollView: 和 scrollViewDidEndZooming:withView:atScale:;此外,最大 (maximumZoomScale) 和最小 (minimumZoomScale) 缩放比例必须不同。我之前的评论也是不正确的。我认为你需要这种额外的方法。

答:

0赞 DonMag 12/18/2020 #1

下面是基于本教程的一种方法:https://www.raywenderlich.com/5758454-uiscrollview-tutorial-getting-started

@interface ViewController ()
{
    UIScrollView *scrollView;
    UIImageView *imageView;
    NSLayoutConstraint *imageViewTopConstraint;
    NSLayoutConstraint *imageViewLeadingConstraint;
    NSLayoutConstraint *imageViewTrailingConstraint;
    NSLayoutConstraint *imageViewBottomConstraint;
}
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // set name of image asset here
    NSString *imageName = @"myImage";
    
    UIImage *img = [UIImage imageNamed:imageName];
    NSAssert(img, @"Failed to load image!");

    scrollView = [UIScrollView new];
    imageView = [UIImageView new];
    
    scrollView.translatesAutoresizingMaskIntoConstraints = NO;
    imageView.translatesAutoresizingMaskIntoConstraints = NO;
    
    imageView.contentMode = UIViewContentModeScaleToFill;
    
    [scrollView addSubview:imageView];
    [self.view addSubview:scrollView];

    // respect safe area
    UILayoutGuide *g = [self.view safeAreaLayoutGuide];
    UILayoutGuide *cg = scrollView.contentLayoutGuide;
    
    imageViewTopConstraint = [imageView.topAnchor constraintEqualToAnchor:cg.topAnchor];
    imageViewLeadingConstraint = [imageView.leadingAnchor constraintEqualToAnchor:cg.leadingAnchor];
    imageViewTrailingConstraint = [imageView.trailingAnchor constraintEqualToAnchor:cg.trailingAnchor];
    imageViewBottomConstraint = [imageView.bottomAnchor constraintEqualToAnchor:cg.bottomAnchor];

    [NSLayoutConstraint activateConstraints:@[
        
        [scrollView.topAnchor constraintEqualToAnchor:g.topAnchor constant:0.0],
        [scrollView.leadingAnchor constraintEqualToAnchor:g.leadingAnchor constant:0.0],
        [scrollView.trailingAnchor constraintEqualToAnchor:g.trailingAnchor constant:0.0],
        [scrollView.bottomAnchor constraintEqualToAnchor:g.bottomAnchor constant:0.0],

        imageViewTopConstraint,
        imageViewLeadingConstraint,
        imageViewTrailingConstraint,
        imageViewBottomConstraint,
        
    ]];
    
    scrollView.delegate = self;
    
    // this will be updated
    scrollView.minimumZoomScale = 0.1;
    
    // desired max zoom scale
    scrollView.maximumZoomScale = 5.0;
    
    imageView.image = img;
    imageView.frame = CGRectMake(0.0, 0.0, img.size.width, img.size.height);

}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self updateMinZoomScaleForSize:scrollView.bounds.size];
    [self updateConstraintsForSize:scrollView.bounds.size];
}

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    return imageView;
}

- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
    [self updateConstraintsForSize:scrollView.frame.size];
}

- (void)centerImage {
    CGFloat yOffset = (scrollView.frame.size.height - imageView.frame.size.height) * 0.5;
    CGFloat xOffset = (scrollView.frame.size.width - imageView.frame.size.width) * 0.5;
    scrollView.contentOffset = CGPointMake(xOffset, yOffset);
}

- (void)updateMinZoomScaleForSize:(CGSize)size {
    UIImage *img = imageView.image;
    if (!img) {
        return;
    }
    
    CGFloat widthScale = size.width / img.size.width;
    CGFloat heightScale = size.height / img.size.height;
    
    CGFloat minScale = MIN(widthScale, heightScale);

    scrollView.minimumZoomScale = minScale;
    scrollView.zoomScale = minScale;
}

- (void)updateConstraintsForSize:(CGSize)size {
    CGFloat yOffset = MAX(0.0, (size.height - imageView.frame.size.height) * 0.5);
    imageViewTopConstraint.constant = yOffset;
    imageViewBottomConstraint.constant = yOffset;
    
    CGFloat xOffset = MAX(0.0, (size.width - imageView.frame.size.width) * 0.5);
    imageViewLeadingConstraint.constant = xOffset;
    imageViewTrailingConstraint.constant = xOffset;
    
    [self.view layoutIfNeeded];
}

@end