ios - UIScrollView 的 subview 保持在同一位置,而 UIScrollView 垂直滚动

标签 ios swift autolayout swift4

谁能告诉我为什么我添加到 UIScrollView 的 subview 不会滚动?当我运行该项目时,我可以上下滚动 UIScrollView,我可以在滚动时看到屏幕右侧的滚动指示器。但是我添加到 UIScrollView 的 subview 保持在相同的位置,就好像它们根本不是 UIScrollView 的 subview 一样。这很奇怪,因为我从我正在使用的另一个 View 复制了大部分代码,并且它的工作完全符合预期,只是这个 View 不起作用。感谢您查看,这是我的代码

import UIKit

class EnterCredentialsVC2: UIViewController {

    private lazy var scrollView: UIScrollView = { [unowned self] in
        let view = UIScrollView()
        view.backgroundColor = UIColor.ricdBlue
        view.contentSize.height = self.view.frame.size.height + 300
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    private let emailTextField: UITextField = { 
        let field = UITextField()
        field.placeholder = "Email Address"
        field.translatesAutoresizingMaskIntoConstraints = false
        return field
    }()

    private let passwordTextField: UITextField = { 
        let field = UITextField()
        field.placeholder = "Password (6 characters minimum)"
        field.translatesAutoresizingMaskIntoConstraints = false
        return field
    }()

    private let enterButton: UIButton = {
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()

    private let errorLabel: UILabel = {
        let label = UILabel()
        label.numberOfLines = 0
        label.minimumScaleFactor = 0.1
        label.adjustsFontSizeToFitWidth = true
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
            layoutView()
    }
}


//view layout methods
extension EnterCredentialsVC2 {
    private func layoutView() {
        layoutScrollView()
        layoutEmailTextField()
        layoutPasswordTextField()
        layoutEnterButton()
        layoutErrorLabel()
    }

    private func layoutScrollView() {
        view.addSubview(scrollView)
        scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        scrollView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
        scrollView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
        scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
    }

    private func layoutEmailTextField() {
        scrollView.addSubview(emailTextField)
        emailTextField.heightAnchor.constraint(equalToConstant: 45).isActive = true
        emailTextField.widthAnchor.constraint(equalToConstant: view.bounds.width * 0.9).isActive = true
        emailTextField.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true
        emailTextField.topAnchor.constraint(equalTo: scrollView.safeAreaLayoutGuide.topAnchor, constant: 100).isActive = true
    }

    private func layoutPasswordTextField() {
        scrollView.addSubview(passwordTextField)
        passwordTextField.heightAnchor.constraint(equalToConstant: 45).isActive = true
        passwordTextField.widthAnchor.constraint(equalToConstant: view.bounds.width * 0.9).isActive = true
        passwordTextField.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true
        passwordTextField.topAnchor.constraint(equalTo: emailTextField.bottomAnchor, constant: 50).isActive = true
    }

    private func layoutEnterButton() {
        scrollView.addSubview(enterButton)
        enterButton.widthAnchor.constraint(equalToConstant: view.bounds.width * 0.5).isActive = true
        enterButton.heightAnchor.constraint(equalToConstant: 55).isActive = true
        enterButton.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true

        let top = enterButton.topAnchor.constraint(equalTo: passwordTextField.bottomAnchor, constant: 50)
        top.priority = .defaultHigh
        top.isActive = true
        let bottom = enterButton.bottomAnchor.constraint(greaterThanOrEqualTo: scrollView.safeAreaLayoutGuide.bottomAnchor, constant: 200)
        bottom.priority = .defaultLow
        bottom.isActive = true
    }

    private func layoutErrorLabel() {
        scrollView.addSubview(errorLabel)
        errorLabel.widthAnchor.constraint(equalToConstant: view.bounds.width-20).isActive = true
        errorLabel.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true

        let top = errorLabel.topAnchor.constraint(equalTo: enterButton.bottomAnchor, constant: 30)
        top.priority = .required
        top.isActive = true

        let bottom = errorLabel.bottomAnchor.constraint(equalTo: scrollView.safeAreaLayoutGuide.bottomAnchor, constant: -20)
        bottom.priority = .defaultLow
        bottom.isActive = true
    }
}

最佳答案

ScrollView 中直接 subview 的约束以一种特殊的方式工作。它们必须固定到 ScrollView 本身或其 contentLayoutGuide。这有一个特殊的含义:“我并没有真正固定在你的外面,我只是向你展示 subview 的布局,我告诉你你的内容大小。”

固定到安全区域布局指南——一个永远不会移动的东西——完全违反了这一点。这就像固定到 ScrollView 的 frameLayoutGuide,或者完全固定到 ScrollView 之外的东西。它特别指示 ScrollView 在计算内容高度时考虑这些 View 。

您已经明确地为 ScrollView 指定了内容大小——在错误的时间以错误的方式,但这是另一回事——并且“幸运地”导致 ScrollView 可以滚动。但是,如果您正确设置了内部约束,则会忽略 contentSize 的任何显式设置。

关于ios - UIScrollView 的 subview 保持在同一位置,而 UIScrollView 垂直滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51718058/

相关文章:

在测试设备上进行身份验证时,iOS SDK 报告 "user denied"

ios - 在 IOS 中使用 GCD 下载图像时如何更新标签文本

ios - 如何在 Swift 中将两个元素(不知道它们的宽度)并排居中?

iOS AVPlayer取消缓冲

ios - 我无法在 Swift 项目的两个目标中使用我的核心数据模型

ios - UITableView 调用 didEndDisplayingCell 不正确

ios - 如何将字符串日期转换为以毫秒为单位的 swift 3

ios - 将其他 View 移动到隐藏的 View

ios - 在 iPhone 5 上如何阻止自动布局拉伸(stretch)弹出框的高度?

ios - 以编程方式使用自动布局将 subview 添加到 UICollectionView 不起作用