使用iOS 14.1 SDK构建时,UIScrollView会忽略iOS 12上的frameLayoutGuide约束 [英] UIScrollView ignores frameLayoutGuide constraints on iOS 12 when built with iOS 14.1 SDK

查看:84
本文介绍了使用iOS 14.1 SDK构建时,UIScrollView会忽略iOS 12上的frameLayoutGuide约束的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在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"

导致症状的约束条件:

  1. scrollview的frameLayoutGuide固定在scrollviewContainerView的顶部/底部/前导/后部
  2. contentView固定在scrollview的contentLayoutGuide的顶部/底部/开头/结尾
  3. 因为这是垂直滚动视图:contentView的widthAnchor固定到scrollView的frameLayoutGuide
  1. scrollview's frameLayoutGuide pinned to top/bottom/leading/trailing of scrollviewContainerView
  2. contentView pinned to top/bottom/leading/trailing of scrollview's contentLayoutGuide
  3. because this is a vertical scrollview: contentView's widthAnchor pinned to scrollView's frameLayoutGuide

症状:在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.

推荐答案

为帮助理解UIScrollViewFrame Layout GuideContent Layout Guide ...

To help understand UIScrollView, Frame Layout Guide and Content Layout Guide...

Frame Layout GuideContent 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屋!

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