Ios 如何在使用自动布局时使UIScrollView仅向一个方向缩放
我试图使UIScrollView只允许在水平方向上缩放。滚动视图采用纯自动布局方法设置。通常的方法如许多堆栈溢出答案(例如)和资源中所建议的那样。在自动布局存在之前,我已经成功地在应用程序中使用了它。方法如下:在滚动视图的内容视图中,我覆盖Ios 如何在使用自动布局时使UIScrollView仅向一个方向缩放,ios,swift,uiscrollview,autolayout,zooming,Ios,Swift,Uiscrollview,Autolayout,Zooming,我试图使UIScrollView只允许在水平方向上缩放。滚动视图采用纯自动布局方法设置。通常的方法如许多堆栈溢出答案(例如)和资源中所建议的那样。在自动布局存在之前,我已经成功地在应用程序中使用了它。方法如下:在滚动视图的内容视图中,我覆盖setTransform(),并将传入的变换修改为仅在x方向缩放: override var transform: CGAffineTransform { get { return super.transform } set {
setTransform()
,并将传入的变换修改为仅在x方向缩放:
override var transform: CGAffineTransform {
get { return super.transform }
set {
var t = newValue
t.d = 1.0
super.transform = t
}
}
我还重置了滚动视图的内容偏移,使其在缩放过程中不会垂直滚动:
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)
}
这在不使用自动布局时非常有效:
但是,使用“自动布局”时,内容偏移在缩放过程中会出错。虽然内容视图仅在水平方向上缩放,但它会垂直移动:
我举了一个例子项目(用来制作这个问题中的视频)。它包含两个情节提要:Main.storyboard和NoAutolayout.storyboard,它们完全相同,只是Main.storyboard启用了自动布局,而NoAutolayout未启用。通过更改主界面项目设置在它们之间切换,您可以看到这两种情况下的行为
我真的不想关闭autolayout,因为它以一种比手动布局更好的方式解决了许多实现UI的问题。在使用autolayout进行缩放时,是否有方法保持垂直内容偏移正确(即零)
编辑:我向示例项目添加了第三个情节提要AutolayoutVariableColumns.storyboard。这将添加一个文本字段来更改GridView中的列数,从而更改其固有的内容大小。这更接近地显示了我在引发这个问题的真实应用程序中需要的行为。我不确定这是否满足您100%自动布局的要求,但这里有一个解决方案,其中
UIScrollView
设置了自动布局,并将gridView
添加为子视图
您的ViewController.swift
应如下所示:
// Add an outlet for the scrollView in interface builder.
@IBOutlet weak var scrollView: UIScrollView!
// Remove the outlet and view for gridView.
//@IBOutlet var gridView: GridView!
// Create the gridView here:
var gridView: GridView!
// Setup some views
override func viewDidLoad() {
super.viewDidLoad()
// The width for the gridView is set to 1000 here, change if needed.
gridView = GridView(frame: CGRect(x: 0, y: 0, width: 1000, height: self.view.bounds.height))
scrollView.addSubview(gridView)
scrollView.contentSize = CGSize(width: gridView.frame.width, height: scrollView.frame.height)
gridView.contentMode = .ScaleAspectFill
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return gridView
}
func scrollViewDidZoom(scrollView: UIScrollView) {
scrollView.contentOffset = CGPoint(x: scrollView.contentOffset.x, y: 0.0)
scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: scrollView.frame.height)
}
尝试设置
translatesAutoResizengMaskintoConstraints
func scrollViewDidZoom(scrollView: UIScrollView) {
gridView.translatesAutoresizingMaskIntoConstraints = true
}
在示例项目中,它起作用。如果这还不够,请尝试在ScrollViewDiEndZooming:
中以编程方式创建新约束
此外,如果这没有帮助,请更新示例项目,以便我们可以使用变量intrinsicContentSize()
这篇由Ole Begemann撰写的文章给了我很大的帮助WWDC 2015视频
幸运的是,这里有一面旗帜。它被称为translatesAutoResizengMask[无空间]约束 这有点多,但基本上是言行一致。它使视图的行为方式与传统布局系统下相同,但在自动布局世界中
我想我明白了。您需要在变换中应用平移以偏移缩放时UIScrollView尝试执行的居中操作 将其添加到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
}
}
}
要计算变换,我们需要知道视图的未缩放高度。这里,我只是在layoutSubviews()期间获取帧大小,并假设它包含未缩放的高度。可能有一些边缘情况是不正确的;在视图更新周期中,计算高度可能是一个更好的方法,但这是基本思想。尽管@Anna的解决方案可行,但UIScrollView提供了一种使用自动布局的方法。但由于滚动视图的工作方式与其他视图略有不同,因此约束的解释也不同:
- 滚动视图的边/边距与其内容之间的约束附加到滚动视图的内容区域
- 高度、宽度或中心之间的约束附加到滚动视图的框架
- 滚动视图和滚动视图外部视图之间的约束与普通视图类似
您可以保留已使用但现在已附加到内容视图的栅格视图约束。对于仅水平缩放,请使代码保持原样。您的
转换
覆盖处理得非常好。谢谢您的回答。不幸的是,我想使用autolayout的全部原因是“GridView”(在我的示例项目中实际上没有GridView那么简单)的大小会根据其内容而变化。Autolayout对intrinsicContentSize()
的支持非常适合于此。如果没有它,视图必须随着内容的更改而手动调整大小,这相当痛苦。我并不介意关闭滚动视图的自动布局,只要它的内容视图可以通过其固有的内容大小来调整大小。啊,明白了。如果我想办法在gridView
上使用autolayout,我会告诉你的!谢谢你的回答。我不完全理解为什么会这样,但我认为它本质上是一个脆弱的h