【问题标题】:Animating a view with AutoLayout but it changes without actually animating使用 AutoLayout 为视图设置动画,但它在没有实际动画的情况下更改
【发布时间】:2018-03-09 17:12:23
【问题描述】:

我有一个自定义视图子类,为了清楚起见,我将提供所有代码。我在下面突出显示了相关部分。

注意:我知道如何使用 AutoLayout 为视图设置动画。问题不在于编写动画代码。问题是它更新了视图,但实际上并没有为任何东西设置动画。它只是跳到新的大小。

class ExpandingButtonView: UIView {
    let titleLabel: UILabel = {
        let l = UILabel()
        l.translatesAutoresizingMaskIntoConstraints = false
        l.textColor = .white
        l.setContentCompressionResistancePriority(UILayoutPriorityRequired, for: .vertical)
        l.setContentHuggingPriority(UILayoutPriorityRequired, for: .vertical)
        return l
    }()

    let buttonStack: UIStackView = {
        let s = UIStackView()
        s.translatesAutoresizingMaskIntoConstraints = false
        s.axis = .vertical
        s.spacing = 8
        s.isLayoutMarginsRelativeArrangement = true
        s.layoutMargins = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
        return s
    }()

    var collapsed: Bool = true {
        didSet {
            animatedCollapsedState()
        }
    }

    lazy var collapsedConstraint: NSLayoutConstraint = {
        return self.bottomAnchor.constraint(equalTo: self.titleLabel.bottomAnchor, constant: 10)
    }()

    lazy var expandedConstraint: NSLayoutConstraint = {
        return self.bottomAnchor.constraint(equalTo: self.buttonStack.bottomAnchor)
    }()

    init(title: String, color: UIColor, buttonTitles: [String]) {
        super.init(frame: .zero)

        translatesAutoresizingMaskIntoConstraints = false
        layer.cornerRadius = 8
        clipsToBounds = true
        backgroundColor = color

        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(toggleCollapsed))
        tapGestureRecognizer.numberOfTapsRequired = 1
        tapGestureRecognizer.numberOfTouchesRequired = 1
        addGestureRecognizer(tapGestureRecognizer)

        titleLabel.text = title
        addSubview(titleLabel)
        addSubview(buttonStack)

        buttonTitles.forEach {
            let button = UIButton(type: .system)
            button.translatesAutoresizingMaskIntoConstraints = false
            button.backgroundColor = UIColor(white: 1.0, alpha: 0.5)
            button.setTitle($0, for: .normal)
            button.tintColor = .white
            button.layer.cornerRadius = 4
            button.clipsToBounds = true
            button.titleLabel?.font = .boldSystemFont(ofSize: 17)
            button.setContentCompressionResistancePriority(UILayoutPriorityRequired, for: .vertical)

            buttonStack.addArrangedSubview(button)
        }

        NSLayoutConstraint.activate([
            collapsedConstraint,
            titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 10),
            titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10),
            titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 10),
            titleLabel.bottomAnchor.constraint(equalTo: buttonStack.topAnchor),
            buttonStack.leadingAnchor.constraint(equalTo: leadingAnchor),
            buttonStack.trailingAnchor.constraint(equalTo: trailingAnchor),
            ])
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func toggleCollapsed() {
        collapsed = !collapsed
    }

    func animatedCollapsedState() {
        UIView.animate(withDuration: 1) {
            self.collapsedConstraint.isActive = self.collapsed
            self.expandedConstraint.isActive = !self.collapsed
            self.layoutIfNeeded()
        }
    }
}

它有两种状态...

  1. 已折叠...

  1. 扩展...

当您点击它时,tapGestureRecognizer 会切换 collapsed 值,该值会触发 didSet,然后会为 UI 设置动画。

动画功能是...

func animatedCollapsedState() {
    UIView.animate(withDuration: 1) {
        self.collapsedConstraint.isActive = self.collapsed
        self.expandedConstraint.isActive = !self.collapsed
        self.layoutIfNeeded()
    }
}

但是...它不是动画。它只是跳转到新的大小而没有实际动画。

我已删除该问题的另一部分视图。在 UI 更改期间还有一个背景图像视图淡入/淡出。那确实动画。所以我不太确定这里发生了什么?

我还尝试将约束更新移出动画块,并尝试在更新之前运行layoutIfNeeded()

在所有情况下,它都会做同样的事情来跳转到新的大小。

【问题讨论】:

    标签: ios swift uiviewanimation


    【解决方案1】:

    你必须在视图的父视图上调用layoutIfNeeded()

    func animatedCollapsedState() {
        self.collapsedConstraint.isActive = self.collapsed
        self.expandedConstraint.isActive = !self.collapsed
        UIView.animate(withDuration: 1) {
            self.superview?.layoutIfNeeded()
        }
    }
    

    【讨论】:

    • 嗯...好的,它现在有动画了(谢谢),但是到处乱跳。我真的被这个难住了。视图似乎正在跳转到最终位置(大小不变),然后对其大小进行动画处理。
    • 好吧……这很奇怪。我不得不做self.superview?.superview?.layoutIfNeeded(),这太糟糕了:(我认为必须探索一种新的方法。不过现在可以了。谢谢:D
    • 我刚刚开始制作视频,以证明它正在工作。 :) 很高兴我能帮上忙!
    猜你喜欢
    • 1970-01-01
    • 2014-03-08
    • 1970-01-01
    • 1970-01-01
    • 2019-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多