使用iOS 14.1 SDK构建时,UIScrollView会忽略iOS 12上的frameLayoutGuide约束 [英] UIScrollView ignores frameLayoutGuide constraints on iOS 12 when built with iOS 14.1 SDK
问题描述
在iOS 12上运行时,我只是浪费了一个小时的时间,看起来像是iOS 14 SDK的回归,所以我认为我会发布此消息,以防它对其他人有所帮助.
I just wasted an hour with what looks like an iOS 14 SDK regression when running on iOS 12 so I thought i'd post this in case it helps others.
摘要:像往常一样,用frameLayoutGuide
固定UIScrollView
的框架和frameLayoutGuide
时,如果滚动视图包含在另一个视图中(在我的情况下),这在iOS 12上会中断在子视图控制器中,不确定是否重要).
Summary: When pinning the frame of the UIScrollView
with the frameLayoutGuide
as we've always done, this breaks on iOS 12 when the scrollview is contained within another view (in my case in a child viewcontroller, not sure if that matters).
设置: 视图设置,所有视图均使用自动版式:
Setup: View setup, all views using autolayout:
UIView "scrollviewContainerView" [fixed/unchanging size]
|
\- UIScrollView "scrollView"
|
\ UIView "contentView"
导致症状的约束条件:
- scrollview的
frameLayoutGuide
固定在scrollviewContainerView的顶部/底部/前导/后部 - contentView固定在scrollview的
contentLayoutGuide
的顶部/底部/开头/结尾 - 因为这是垂直滚动视图:contentView的
widthAnchor
固定到scrollView的frameLayoutGuide
- scrollview's
frameLayoutGuide
pinned to top/bottom/leading/trailing of scrollviewContainerView - contentView pinned to top/bottom/leading/trailing of scrollview's
contentLayoutGuide
- because this is a vertical scrollview: contentView's
widthAnchor
pinned to scrollView'sframeLayoutGuide
症状:在iOS 14上,一切正常.在iOS 12上滚动时,UIScrollView
本身的大小发生变化,似乎忽略了frameLayoutGuide
约束(即使它们仍然存在:调试iOS 12的结果集之间的视图层次结构时,我看不出任何区别)约束和iOS 14).这使事情看起来非常破损.
Symptom: On iOS 14, everything looks fine. On iOS 12 when scrolling, the size of the UIScrollView
itself changes, seemingly ignoring the frameLayoutGuide
constraints (even though they're still there: I couldn't see any difference when debugging the view hierarchy between iOS 12's resulting set of constraints and iOS 14). This makes things look very very broken.
推荐答案
为帮助理解UIScrollView
,Frame Layout Guide
和Content Layout Guide
...
To help understand UIScrollView
, Frame Layout Guide
and Content Layout Guide
...
Frame Layout Guide
和Content Layout Guide
,部分是为了消除帧与内容的歧义,并允许添加非滚动"内容.滚动视图中的元素.
Frame Layout Guide
and Content Layout Guide
were introduced in iOS 11, in part to eliminate the ambiguity of frame vs content, as well as to allow adding "non-scrolling" elements to the scroll view.
对于以下每个示例,我都像这样添加和约束滚动视图:
For each of the following examples, I'm adding and constraining the scroll view like this:
let scrollView: UIScrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
// respect safe area
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// constrain scrollView 20-pts on each side
scrollView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
scrollView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0),
])
// so we can see the scroll view's frame
scrollView.backgroundColor = .red
现在,考虑旧的"添加内容的方式:
Now, consider the "old" way of adding content:
// call a func to get a vertical stack view with 30 labels
let stackView = createStackView()
scrollView.addSubview(stackView)
NSLayoutConstraint.activate([
// old method
// constrain stack view to scroll view itself
// this defines the "scrollable" content
// stack view Top / Leading / Trailing / Bottom to scroll view
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 0.0),
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 0.0),
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: 0.0),
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 0.0),
// we want vertical scrolling, so we want our content to be only as wide as
// the scroll view itself
stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, constant: 0.0),
])
虽然有些模棱两可,但很简单.通过约束其底部锚点,我是否使堆栈视图仅与滚动视图一样高?如果它是任何其他UIView
的子视图,那就是我所期望的!
Fairly straightforward, although a little ambiguous. Am I making the stack view only as tall as the scroll view, by constraining its bottom anchor? That's what I'd expect if it's a subview of any other UIView
!
因此,请考虑新的"方式:
So, consider the "new" way of doing it:
// call a func to get a vertical stack view with 30 labels
let stackView = createStackView()
scrollView.addSubview(stackView)
let contentG = scrollView.contentLayoutGuide
let frameG = scrollView.frameLayoutGuide
NSLayoutConstraint.activate([
// constrain stack view to scroll view's Content Layout Guide
// this defines the "scrollable" content
// stack view Top / Leading / Trailing / Bottom to scroll view's Content Layout Guide
stackView.topAnchor.constraint(equalTo: contentG.topAnchor, constant: 0.0),
stackView.leadingAnchor.constraint(equalTo: contentG.leadingAnchor, constant: 0.0),
stackView.trailingAnchor.constraint(equalTo: contentG.trailingAnchor, constant: 0.0),
stackView.bottomAnchor.constraint(equalTo: contentG.bottomAnchor, constant: 0.0),
// we want vertical scrolling, so we want our content to be only as wide as
// the scroll view's Frame Layout Guide
stackView.widthAnchor.constraint(equalTo: frameG.widthAnchor, constant: 0.0),
])
现在,很明显,我正在使用堆栈视图来定义可滚动内容".通过将其约束为.contentLayoutGuide
并使用滚动视图的实际框架(其.frameLayoutGuide
)来定义堆栈视图的宽度.
Now, it's very clear that I am using the stack view to define the "scrollable content" by constraining it to the .contentLayoutGuide
and using the scroll view's actual frame (its .frameLayoutGuide
) to define the stack view's width.
此外,假设我希望UI元素(例如图像视图)位于滚动视图内,但我不希望它滚动吗? 旧方式"指的是老方法".将需要将图像视图添加为覆盖在滚动视图顶部的兄弟视图.
In addition, suppose I want a UI element - such as an image view - to be inside the scroll view, but I don't want it to scroll? The "old way" would require adding the image view as a sibling view overlaid on top of the scroll view.
但是现在,通过使用.frameLayoutGuide
,我可以将其添加为非滚动式"广告素材.滚动视图内的元素:
But now, by using .frameLayoutGuide
, I can add it as a "non-scrolling" element inside the scroll view:
guard let img = UIImage(named: "scrollSample") else {
fatalError("could not load image")
}
let imgView = UIImageView(image: img)
imgView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(imgView)
NSLayoutConstraint.activate([
// constrain image view to the Frame Layout Guide
// at top-right, with 20-pts Top / Trailing "padding"
imgView.topAnchor.constraint(equalTo: frameG.topAnchor, constant: 20.0),
imgView.trailingAnchor.constraint(equalTo: frameG.trailingAnchor, constant: -20.0),
// 120 x 120 pts
imgView.widthAnchor.constraint(equalToConstant: 120.0),
imgView.heightAnchor.constraint(equalToConstant: 120.0),
])
现在,我约束到scrollView的.contentLayoutGuide
的所有元素都将滚动,但是约束到scrollView的.frameLayoutGuide
的图像视图将保持不变.
Now, any elements I constrain to the scrollView's .contentLayoutGuide
will scroll, but the image view constrained to the scrollView's .frameLayoutGuide
will remain in place.
这篇关于使用iOS 14.1 SDK构建时,UIScrollView会忽略iOS 12上的frameLayoutGuide约束的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!