【问题标题】:How to zoom a view in UIScrollView with anchor point in center?如何在 UIScrollView 中以锚点为中心缩放视图?
【发布时间】:2011-12-30 12:48:59
【问题描述】:

我在 UIScrollView 中有一个视图,用户可以在其中放大。

视图与 UIScrollView 框架的大小相同。但是,该视图的子视图更大且居中。它是一个与 UIScrollView 大小相同且内容居中的容器。

缩小时,UIScrollView 会通过左上角的锚点而不是居中的锚点来更改内容的比例。

有没有办法改变这种行为,以便在放大或缩小时相对于中心而不是左上角进行缩放?

【问题讨论】:

    标签: iphone objective-c ios uiscrollview


    【解决方案1】:

    可以将行为更改为围绕中心进行缩放,但该技术很棘手。

    假设您有一个大小为 (300,300) 的滚动视图,其中包含一个可缩放的子视图 self.imageView,最初位于 (0,0,300,300)。现在你想缩小。正在发生的事情是,当您缩小时,contentOffset 始终保持 (0,0)。这会导致您使用左上角的锚点进行缩放。

    但是,在这里更改任何视图上的锚点都无济于事;这是因为滚动视图的缩放行为不仅仅是应用于某些子视图的缩放转换。滚动视图中内容的外观由contentInsetcontentOffset 控制,它们是滚动视图维护的独立变量。您需要在缩放期间修改内容偏移和内容插入的行为。

    一种解决方案是在滚动视图滚动时动态调整contentInset。目的是使图像始终居中于滚动视图的可见区域。

    在初始化滚动视图时,像这样准备它的框架:

     - (void) viewDidLoad {
          //// .......
          self.scrollView.zoomScale = 1;
          self.scrollView.minimumZoomScale = fminf(1, fminf(self.scrollView.frame.size.width/(self.imageView.image.size.width+1), self.scrollView.frame.size.height/(self.imageView.image.size.height+1)));
          CGFloat leftMargin = (self.scrollView.frame.size.width - self.imageView.image.size.width)*0.5;
          CGFloat topMargin = (self.scrollView.frame.size.height - self.imageView.image.size.height)*0.5;
          self.imageView.frame = CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height);
          [self assignInsetsOnScroller]; // this has to be done before settings contentOffset!
          self.scrollView.contentOffset = CGPointMake(fmaxf(0,-leftMargin), fmaxf(0,-topMargin));
          self.scrollView.contentSize = CGSizeMake(fmaxf(self.imageView.image.size.width, self.scrollView.frame.size.width+1), fmaxf(self.imageView.image.size.height, self.scrollView.frame.size.height+1));
       }
    

    为滚动视图设置一个委托,覆盖scrollViewDidScroll:,然后执行以下操作:

     - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
        [self assignInsetsOnScroller];
     }
     - (void) assignInsetsOnScroller {
        CGFloat leftMargin = (scrollView.frame.size.width - self.imageView.frame.size.width)*0.5;
        CGFloat topMargin = (scrollView.frame.size.height - self.imageView.frame.size.height)*0.5;
        scrollView.contentInset = UIEdgeInsetsMake(fmaxf(0, topMargin), fmaxf(0, leftMargin), 0, 0);
     }
    

    每个捏合手势都会产生滚动动作。结果是动态调整了插图,因此imageView 总是出现在滚动视图的中心。


    Swift 5:要简单得多。无需进行任何设置 — 只需在 scrollViewDidScroll 中设置 contentOffset

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let leftMargin = (scrollView.bounds.width - imageView.frame.width) * 0.5
        let topMargin = (scrollView.bounds.height - imageView.frame.height) * 0.5
        scrollView.contentInset = UIEdgeInsets(top: topMargin, left: leftMargin, bottom: 0, right: 0)
    }
    

    【讨论】:

    • 这有帮助,谢谢!我认为这应该是公认的答案。
    • 完美运行!
    【解决方案2】:

    是的,我相信您可以更改视图层的anchorPoint。像这样 -

    [self.yourView.layer setAnchorPoint:CGPointMake(0.5, 0)];
    

    锚点的坐标在这张图中被恰当地定义了——

    如果您希望动画从左中心锚定,则将 anchorPoint 设置为(0.0, 0.5),即图中的点 B。

    【讨论】:

    • anchorPoint 将在您对普通视图设置转换时起作用。但它不会影响滚动视图内容的行为。请参阅下面的答案。
    猜你喜欢
    • 2012-12-10
    • 2011-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多