【问题标题】:UIView loaded from Xib does not apply AutoLayout correctly从 Xib 加载的 UIView 未正确应用 AutoLayout
【发布时间】:2018-07-27 03:20:11
【问题描述】:

我正在尝试将我的视图控制器内容分解为从 xib 加载的更小的单个视图块。为此,我将占位符 UIView 对象放入我的 Storyboard 视图控制器中,并使用它们添加实际的 UIView 子类,该子类在构建时作为子视图放置在 xib 文件中。

这个过程非常简单,是discussedbefore

然而,问题在于,在我添加视图时,在 xib 文件中定义的 AutoLayout 约束不起作用。

为了说明这个问题,我创建了一个示例项目:ViewController 有一个 colorView 类型为 CustomColorViewUIView 的子类),它将被添加到一个普通的 UIView 占位符中。 CustomColorViewclass 然后具有coloredView 的属性,它应该填满整个空间(由 xib 文件中每一侧的 AutoLayout 约束定义)。

NibLoadable协议:

public protocol NibLoadable {
    static var nibName: String { get }
}

public extension NibLoadable where Self: UIView {

    public static var nibName: String {
        return String(describing: Self.self)
    }

    public static var nib: UINib {
        let bundle = Bundle(for: Self.self)
        return UINib(nibName: Self.nibName, bundle: bundle)
    }

    func setupFromNib() {
        guard let loadedView = Self.nib.instantiate(withOwner: self, options: nil).first as? UIView else { fatalError("Error loading \(self) from nib") }
        loadedView.frame = bounds

        addSubview(loadedView)
        loadedView.translatesAutoresizingMaskIntoConstraints = false
        loadedView.leadingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.leadingAnchor, constant: 0).isActive = true
        loadedView.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
        loadedView.trailingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.trailingAnchor, constant: 0).isActive = true
        loadedView.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor, constant: 0).isActive = true
    }
}

当我将自定义视图添加到普通的UIView 时,我会假设它应用了 nib 文件中定义的所有约束,但事实并非如此。 print 两个视图的结果应该相同,但它们不同(coloredView 仍然具有来自 xib 文件的大小)。

对可能出现的问题有任何想法吗?感谢您的帮助!

整个项目都在 GitHub 上:XibAutoLayoutExample

【问题讨论】:

  • 整个视图控制器应该用蓝色视图填充?
  • 您的视图高度正确,请添加layer.borderColor和layer.borderWidth并检查它
  • 您无法在viewDidLoad 上获得正确的帧,因为它将开始加载和布局视图,您可以在viewDidLayoutSubviews 上检查实际值。
  • 我的回答对您有任何帮助吗? @JanApotheker

标签: ios autolayout storyboard xib ios-autolayout


【解决方案1】:

您的视图高度正确请添加layer.borderColorlayer.borderWidth并检查它

func setup() {
    print("CustomColorView bounds: \(bounds)")
    print("coloredView subview bounds: \(coloredView.bounds)")
    self.coloredView.layer.borderColor = UIColor.red.cgColor
    self.coloredView.layer.borderWidth = 1
}

此外,如果您在 viewDidAppear 中调用 setup() 将显示正确的值,这是因为 viewDidAppearviewDidLayoutSubviews 之后执行,因此当您的 viewController 正确结束其布局时,您的日志将显示正确的值

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    colorView.setup()
}

日志

CustomColorView bounds: (0.0, 0.0, 320.0, 227.0)
coloredView subview bounds: (0.0, 0.0, 320.0, 227.0)

【讨论】:

  • 我同意您的看法,即viewWillAppear 不保证您将获得正确的值。你应该把它放在viewDidLayoutSubviews
  • 是的,没错,但viewDidAppearviewDidLayoutSubviews 之后执行,因为我认为(如果我错了,请纠正我)所以我使用viewDidAppear 而不是viewWillAppear @EridB
  • 事实上如果你把colorView.setup() 放入viewWillAppear 会得到同样的错误值@EridB
  • 你是对的,我看错了,我没注意到是viewDidAppear。在这种情况下,这是正确的答案! P.S 最好的做法是检查viewDidLayoutSubviews,因为您可能有在视图出现后手动布局的视图!
  • 你是对的,无论如何我已经更新了我的答案,并进一步澄清@EridB
猜你喜欢
  • 1970-01-01
  • 2015-04-08
  • 1970-01-01
  • 1970-01-01
  • 2020-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-01
相关资源
最近更新 更多