动画约束时高度锚点上的自动布局错误

时间:2019-07-03 12:16:38

标签: ios swift uiview autolayout uiviewanimationtransition

我需要在应用程序的页脚处呈现UIView,当用户采取某种操作时,该视图会滚动到视图顶部并固定在位置。

想象一下几乎动画到导航栏的标签栏视图。

example of requirement

从本质上讲,我对视图有2个锚点(顶部和底部)进行了嘲笑。

然后我切换这些锚点,并使用UIView.animatelayoutIfNeeded来移动位置。

然后,将组件的内容锚定到父级的安全区域,这意味着我避免了X系列上出现的顶部和底部问题。

但是,当我的视图开始动画时,我在终端中遇到自动布局错误

(
    "<NSLayoutConstraint:0x600002e38ff0 UILabel:0x7fe64bc04570'Foo Bar Boo Baz'.height == 44   (active)>",
    "<NSLayoutConstraint:0x600002e38d70 UILabel:0x7fe64bc04570'Foo Bar Boo Baz'.top == UILayoutGuide:0x600003408d20'UIViewSafeAreaLayoutGuide'.top   (active)>",
    "<NSLayoutConstraint:0x600002e38e10 UILabel:0x7fe64bc04570'Foo Bar Boo Baz'.bottom == UILayoutGuide:0x600003408d20'UIViewSafeAreaLayoutGuide'.bottom   (active)>",
    "<NSLayoutConstraint:0x600002e39130 UIView:0x7fe64bc166b0.bottom == Home.AnimatedCustomNavigationView:0x7fe64bc02970.bottom   (active)>",
    "<NSLayoutConstraint:0x600002e390e0 V:|-(0)-[UIView:0x7fe64bc166b0]   (active, names: '|':Home.AnimatedCustomNavigationView:0x7fe64bc02970 )>",
    "<NSLayoutConstraint:0x600002e41810 'UIView-Encapsulated-Layout-Height' Home.AnimatedCustomNavigationView:0x7fe64bc02970.height == 896   (active)>",
    "<NSLayoutConstraint:0x600002e38cd0 'UIViewSafeAreaLayoutGuide-bottom' V:[UILayoutGuide:0x600003408d20'UIViewSafeAreaLayoutGuide']-(34)-|   (active, names: '|':UIView:0x7fe64bc166b0 )>",
    "<NSLayoutConstraint:0x600002e38c30 'UIViewSafeAreaLayoutGuide-top' V:|-(0)-[UILayoutGuide:0x600003408d20'UIViewSafeAreaLayoutGuide']   (active, names: '|':UIView:0x7fe64bc166b0 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x600002e38ff0 UILabel:0x7fe64bc04570'Foo Bar Boo Baz'.height == 44   (active)>

这似乎是由高度锚点引起的。

我不确定如何实现此效果并解决此错误。

import UIKit

class AnimatedCustomNavigationView: UIView {

    private lazy var navBar = UIView(frame: .zero)

    private var navBarTopAnchor: NSLayoutConstraint!
    private var navBarBottomAnchor: NSLayoutConstraint!

    override init(frame: CGRect) {
        super.init(frame: frame)

        backgroundColor = theme.color(.background)
        navBar.backgroundColor = .purple

        let label = UILabel(frame: .zero)
        label.text = "Foo Bar Boo Baz"
        label.sizeToFit()


        addSubview(navBar)
        navBar.addSubview(label)

        [navBar, label].forEach { $0.translatesAutoresizingMaskIntoConstraints = false }

        NSLayoutConstraint.activate([

            // MARK: - NavBar Container

            navBar.leadingAnchor.constraint(equalTo: self.leadingAnchor),
            navBar.trailingAnchor.constraint(equalTo: self.trailingAnchor),


            // MARK: - Label

            label.topAnchor.constraint(equalTo: navBar.safeAreaLayoutGuide.topAnchor),
            label.leadingAnchor.constraint(equalTo: navBar.leadingAnchor, constant: 16),
            label.bottomAnchor.constraint(equalTo: navBar.safeAreaLayoutGuide.bottomAnchor),
            label.trailingAnchor.constraint(equalTo: navBar.trailingAnchor, constant: -16),

            label.heightAnchor.constraint(equalToConstant: 44)
        ])

        navBarTopAnchor = navBar.topAnchor.constraint(equalTo: topAnchor)
        navBarTopAnchor.isActive = false

        navBarBottomAnchor = navBar.bottomAnchor.constraint(equalTo: bottomAnchor)
        navBarBottomAnchor.isActive = true



        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            self.navBarTopAnchor.isActive = true
            self.navBarBottomAnchor.isActive = false
            UIView.animate(withDuration: 1.5, delay: 0, options: .curveEaseInOut, animations: {
                self.layoutIfNeeded()
            }, completion: nil)
        }
    }

    required init?(coder aDecoder: NSCoder) {
        return nil
    }
}

要暂时模拟用户操作,我将动画调用包装在DispatchQueue.main.asyncAfter

1 个答案:

答案 0 :(得分:1)

您需要正确订购.isActive = false之前的.isActive = true

DispatchQueue.main.asyncAfter(deadline: .now() + 2) {  
        self.navBarBottomAnchor.isActive = false
        self.navBarTopAnchor.isActive = true
        UIView.animate(withDuration: 1.5, delay: 0, options: .curveEaseInOut, animations: {
            self.layoutIfNeeded()
        }, completion: nil)
}