使用自动布局时如何使 UIScrollView 仅向一个方向缩放 [英] How to make UIScrollView zoom in only one direction when using auto layout

查看:19
本文介绍了使用自动布局时如何使 UIScrollView 仅向一个方向缩放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使 UIScrollView 只允许在水平方向上缩放.滚动视图是使用纯自动布局方法设置的.通常的方法是在许多 Stack Overflow 答案(例如

但是,当使用自动布局时,内容偏移在缩放过程中最终会出错.虽然内容视图仅在水平方向缩放,但它会垂直移动:

我在 GitHub 上放了一个示例项目 (用于制作此问题中的视频).它包含两个故事板,Main.storyboard 和 NoAutolayout.storyboard,除了 Main.storyboard 启用了自动布局而 NoAutolayout 没有之外,它们是相同的.通过更改主界面项目设置在它们之间切换,您可以看到两种情况下的行为.

我真的不想关闭自动布局,因为它以比手动布局所需的更好的方式解决了许多实现 UI 的问题.有没有办法在使用自动布局进行缩放时保持垂直内容偏移正确(即零)?

我在示例项目中添加了第三个故事板 AutolayoutVariableColumns.storyboard.这会添加一个文本字段来更改 GridView 中的列数,从而更改其固有内容大小.这更接近地显示了我在提示此问题的真实应用中需要的行为.

解决方案

我想我想通了.您需要在转换中应用平移以抵消 UIScrollView 在缩放时尝试做的居中.

将此添加到您的 GridView:

var unzoomedViewHeight: CGFloat?覆盖 func layoutSubviews() {super.layoutSubviews()unzoomedViewHeight = frame.size.height}覆盖 var 变换:CGAffineTransform {得到 { 返回超级转换 }放 {如果让 unzoomedViewHeight = unzoomedViewHeight {var t = 新值t.d = 1.0t.ty = (1.0 - t.a) * unzoomedViewHeight/2super.transform = t}}}

要计算变换,我们需要知道视图的未缩放高度.在这里,我只是在 layoutSubviews() 期间获取帧大小并假设它包含未缩放的高度.可能存在一些不正确的极端情况;在视图更新周期中计算高度可能是一个更好的地方,但这是基本思想.

I'm attempting to make a UIScrollView only allow zooming in the horizontal direction. The scroll view is setup with a pure autolayout approach. The usual approach is as suggested in a number of Stack Overflow answers (e.g. this one) and other resources. I have successfully used this in apps before autolayout existed. The approach is as follows: in the scroll view's content view, I override setTransform(), and modify the passed in transform to only scale in the x direction:

override var transform: CGAffineTransform {
    get { return super.transform }
    set {
        var t = newValue
        t.d = 1.0
        super.transform = t
    }
}

I also reset the scroll view's content offset so that it doesn't scroll vertically during the zoom:

func scrollViewDidZoom(scrollView: UIScrollView) {
    scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: scrollView.frame.height)
    scrollView.contentOffset = CGPoint(x: scrollView.contentOffset.x, y: 0.0)
}

This works very nicely when not using autolayout:

However, when using autolayout, the content offset ends up wrong during zooming. While the content view only scales in the horizontal direction, it moves vertically:

I've put an example project on GitHub (used to make the videos in this question). It contains two storyboards, Main.storyboard, and NoAutolayout.storyboard, which are identical except that Main.storyboard has autolayout turned on while NoAutolayout does not. Switch between them by changing the Main Interface project setting and you can see behavior in both cases.

I'd really rather not switch off autolayout as it solves a number of problems with implementing my UI in a much nicer way than is required with manual layout. Is there a way to keep the vertical content offset correct (that is, zero) during zooming with autolayout?

EDIT: I've added a third storyboard, AutolayoutVariableColumns.storyboard, to the sample project. This adds a text field to change the number of columns in the GridView, which changes its intrinsic content size. This more closely shows the behavior I need in the real app that prompted this question.

解决方案

Think I figured it out. You need to apply a translation in the transform to offset the centering UIScrollView tries to do while zooming.

Add this to your GridView:

var unzoomedViewHeight: CGFloat?
override func layoutSubviews() {
    super.layoutSubviews()
    unzoomedViewHeight = frame.size.height
}

override var transform: CGAffineTransform {
    get { return super.transform }
    set {
        if let unzoomedViewHeight = unzoomedViewHeight {
            var t = newValue
            t.d = 1.0
            t.ty = (1.0 - t.a) * unzoomedViewHeight/2
            super.transform = t
        }
    }
}

To compute the transform, we need to know the unzoomed height of the view. Here, I'm just grabbing the frame size during layoutSubviews() and assuming it contains the unzoomed height. There are probably some edge cases where that's not correct; might be a better place in the view update cycle to calculate the height, but this is the basic idea.

这篇关于使用自动布局时如何使 UIScrollView 仅向一个方向缩放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆