【问题标题】:Why is my UIView not displaying correctly when updating autolayout constraints?为什么更新自动布局约束时我的 UIView 无法正确显示?
【发布时间】:2020-10-04 04:32:35
【问题描述】:

我正在尝试为一个简单的自动布局约束更改设置动画,但是当我第一次调用它时它会设置动画,而不是仅仅拉伸和更改高度,它会向上移动整个视图,如果我再次调用它,它会自行修复.

这是我设置约束的方式:

hiddenView.addSubview(topView)
                    topView.translatesAutoresizingMaskIntoConstraints = false
                    topView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

            topView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
            topView.bottomAnchor.constraint(equalTo: hiddenView.bottomAnchor).isActive = true

            topViewDefaultTopAnchorConstraints.append(topView.topAnchor.constraint(equalTo: hiddenView.centerYAnchor))
            topViewSelectedTopAnchorConstraints.append(topView.topAnchor.constraint(equalTo: hiddenView.topAnchor))

            NSLayoutConstraint.activate(topViewDefaultTopAnchorConstraints)

这是我更新它们的方式:

func showTopView() {
    NSLayoutConstraint.deactivate(topViewDefaultTopAnchorConstraints)
    NSLayoutConstraint.activate(topViewSelectedTopAnchorConstraints)
    UIView.animate(withDuration: 0.25) {
        self.view.layoutIfNeeded()
    }
}

更新: 这是调用 showTopView 时发生的情况的 gif 图像,再次调用它会修复底部约束:

它应该只是像第二张图片那样动画,而不是把整个视图都向上,因为 bottomAnchor 没有改变,我该如何解决这个问题?

更新:我意识到我正在圆角 topViewbottomView,如果我不圆角,那么它可以正常工作,所以它与此有关。

override func viewDidLayoutSubviews() {
    topView.roundCorners(corners: [.topLeft, .topRight], radius: 100*ScreenDimensions.ASPECT_RATIO_RESPECT_OF_XMAX)
    bottomView.roundCorners(corners: [.topLeft, .topRight], radius: 100*ScreenDimensions.ASPECT_RATIO_RESPECT_OF_XMAX)
    topConstraint = topView.topAnchor.constraint(equalTo: hiddenView.topAnchor, constant: hiddenView.frame.height/2)
    topConstraint.isActive = true
}

【问题讨论】:

  • 您确定您的图片可以像图片 2 中那样拉伸吗?

标签: swift xcode uiview autolayout constraints


【解决方案1】:

似乎hiddenViewbottomAnchortopView 的底部一起被拉高了。确保hiddenView 的bottomAnchor 被正确约束。更好的方法是提供一个heightAnchor 并增加 heightConstraint 常量值以动画视图以增加高度。

【讨论】:

  • 我尝试了heightAnchor,第一次它似乎仍然向上移动了整个东西,我确定底部锚点受到了适当的约束。
  • 在使用heightAnchor 时,您是否删除了topAnchor?如果你没有,你应该这样做。
  • 是的,我用heightAnchor 替换了topAnchor,但结果相同。现在我只是让底部锚点加长来补偿,但这并不理想。
【解决方案2】:

我想我知道你的问题是什么。您可能需要使用常量,而不是定义两个不同的约束来激活/停用。

  • 首先,在 ViewController 的顶部定义一个约束,如下所示:
var topConstraint: NSLayoutConstraint!
  • 然后,如下所示进行初始化:

      hiddenView.addSubview(topView)
      topView.translatesAutoresizingMaskIntoConstraints = false
      topView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    
      topView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
      topView.bottomAnchor.constraint(equalTo: hiddenView.bottomAnchor).isActive = true
      topConstraint = topView.topAnchor.constraint(equalTo: hiddenView.topAnchor, constant: hiddenView.frame.height/2)
      topConstraint.isActive = true            
    
  • 然后在 showTopView 中,您只需要更新常量即可创建您正在寻找的动画:

    func showTopView() {
        topConstraint.isActive = false            
        topConstraint.constant = 0
        topConstraint.isActive = true            
        UIView.animate(withDuration: 0.25) {
            self.view.layoutIfNeeded()
        }
    }

同样,如果你想让视图恢复正常,你可以按如下方式实现:

    func hideTopView() {
        topConstraint.isActive = false            
        topConstraint.constant = hiddenView.frame.height/2
        topConstraint.isActive = true            
        UIView.animate(withDuration: 0.25) {
            self.view.layoutIfNeeded()
        }
    }

【讨论】:

  • 我已经拥有centerXAnchor,所以我认为这不是问题。
  • 我更新了我的答案。我的错,我没有看到你定义了centerXAnchor
  • 试过你的答案,它仍然是一样的。似乎真的不知道为什么会这样做,但是一旦再次调用showTopView(),它就会在没有动画的情况下拉伸底部。奇怪的是它第一次不起作用,想知道它是否与hiddenView 有关,但由于它落后,我认为不会。
  • 这很好。您可以发布 hiddenView 的约束条件吗?
  • 实际上,我刚刚意识到这绝对与我如何将视图的角落四舍五入有关,如果我不四舍五入到 topView 角落它可以工作,而且他们需要在viewDidLayoutSubViews 中四舍五入,因此当约束发生变化时,它必须以某种方式打破它。我认为...
【解决方案3】:

这种方法可能会让你的运气更好:

override func viewDidLayoutSubviews() {

    super.viewDidLayoutSubviews()

    let r = 100*ScreenDimensions.ASPECT_RATIO_RESPECT_OF_XMAX

    topView.layer.cornerRadius = r
    topView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]

    bottomView.layer.cornerRadius = r
    bottomView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-06
    • 2017-12-24
    • 2017-11-03
    • 1970-01-01
    • 1970-01-01
    • 2014-01-27
    相关资源
    最近更新 更多