在Swift中布局后获取UIScrollView的高度

Jas*_*ady 0 uiscrollview swift3 xcode8

我有一种情况,我正在使用UIScrollView来帮助使用较小手机的用户查看窗口内的全文.我想要显示一个图像图标,如果他们需要滚动(只是为了让他们知道窗口内有更多)但我在使用Swift找到滚动视图的高度时遇到了问题.

这是我的对象的层次结构

在此输入图像描述

基本上,这4个标签适合4.7"iPhone而不是4"iPhone.我尝试设置一些逻辑来检查UIScrollView内容是否大于窗口,但它似乎没有工作.我一直认为高度为零.

我使用scrollHeight = scrollView.contentSize.height,并试图把那里面viewDidLoad(),viewWillAppear()和viewDidLayoutSubviews()但每次它最终被0.

contentSize我应该用它来检查高度是正确的吗?

pau*_*lvs 11

TL; DR;

作为一般指南,自动布局无法在viewDidLoad调用时完成视图的大小(内部也不正确viewDidLayoutSubviews).为了确保所有的意见和他们的子视图有自己的正确尺寸查询其之前bounds或者frame,这样做:

self.view.setNeedsLayout()
self.view.layoutIfNeeded()
print(self.someSubview.frame) // gives correct frame
Run Code Online (Sandbox Code Playgroud)

说明

有点违反直觉,将代码放在里面viewDidLayoutSubviews并不意味着Auto Layout会给出所有子视图的正确大小.引用此方法的文档:

但是,调用此方法并不表示已调整视图子视图的各个布局.

这意味着:在内部viewDidLayoutSubviews,只有第一层次的子视图将具有正确的大小(即子视图而不是"孙视图").


这是我创建的示例布局(红色视图是子视图,蓝色视图是孙视图).

关于这个例子的一些要点:

  • 所有视图都使用自动布局约束定位到其父视图(固定边距,但不是固定宽度),这允许它们根据我运行此模拟器的屏幕大小增大或缩小.
  • 我在故事板中使用了iPhone 7大小的视图控制器,并在iPhone 7 Plus模拟器上运行了示例.这意味着我可以确定视图会有所增长并使用它来确定视图是否具有其原始大小或最终大小.

请注意,在Interface Builder中,子视图的原始宽度(红色)为240磅,孙子视图的原始宽度(蓝色)为200磅.

演示

以下是代码:

class ViewController: UIViewController {

    @IBOutlet weak var childView: UIView!
    @IBOutlet weak var grandchildView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()
        print("child     ", #function, childView.frame.size.width)
        print("grandchild", #function, grandchildView.frame.size.width)
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        print("child     ", #function, childView.frame.size.width)
        print("grandchild", #function, grandchildView.frame.size.width)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        print("child     ", #function, childView.frame.size.width)
        print("grandchild", #function, grandchildView.frame.size.width)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        print("child     ", #function, childView.frame.size.width)
        print("grandchild", #function, grandchildView.frame.size.width)
    }
}
Run Code Online (Sandbox Code Playgroud)

这是输出:

child      viewDidLoad() 240.0
grandchild viewDidLoad() 200.0
child      viewWillAppear 240.0
grandchild viewWillAppear 200.0
child      viewDidLayoutSubviews() 271.0 // `child` has it's final width now
grandchild viewDidLayoutSubviews() 200.0 // `grandchild` still has it's original width!

// By now, in MOST cases, all views will have their correct sizes.
child      viewDidAppear 271.0
grandchild viewDidAppear 231.0
Run Code Online (Sandbox Code Playgroud)

您可以从此输出中看到的是,viewDidLayoutSubviews 不保证通过View Controller的主视图的直接子视图的任何内容都具有正确的大小.

注意:通常在viewDidAppear调用时,视图的大小正确,但我认为这绝不是保证.

  • 哇!你刚刚解决了我遇到的一个与这个问题无关的问题!我一生都无法弄清楚为什么我正在加载的视图中的框架尺寸错误,但这纠正了这个问题。我将 `setNeedsLayout()` 和 `layoutIfNeeded()` 放在我的 `viewDidLoad()` 中,问题就消失了。 (2认同)