使用 NSLayoutConstraints 在 UIView 上简单滑动动画

Posted

技术标签:

【中文标题】使用 NSLayoutConstraints 在 UIView 上简单滑动动画【英文标题】:Simple slide up animation on UIView using NSLayoutConstraints 【发布时间】:2020-05-03 18:09:25 【问题描述】:

我花了一段时间试图弄清楚这一点,但我就是做不到。我在这里可能缺少一些非常简单的东西。我正在尝试为从底部进入的视图设置动画。这是我用于视图的代码:

private let undoView: UIView = 
    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.backgroundColor = .white
    view.layer.cornerRadius = 15
    view.layer.shadowOffset = .zero
    view.layer.shadowOpacity = 0.3
    view.layer.shadowRadius = 5
    view.layer.shouldRasterize = true
    view.layer.rasterizationScale = UIScreen.main.scale

    let button = UIButton()
    button.translatesAutoresizingMaskIntoConstraints = false
    button.setTitle("Undo", for: .normal)
    button.titleLabel?.textAlignment = .center
    button.setTitleColor(.systemBlue, for: .normal)
    let buttonConstraints = [
        button.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
        button.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
        button.topAnchor.constraint(equalTo: view.topAnchor, constant: 16),
        button.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -16)
    ]
    view.addSubview(button)
    NSLayoutConstraint.activate(buttonConstraints)

    let swipeGesture = UISwipeGestureRecognizer(target: view, action: #selector(undoViewSwiped))
    view.addGestureRecognizer(swipeGesture)

    return view
()

这是我用来尝试实现动画的代码:

func addUndoView() 
    var bottomConstraint = undoView.topAnchor.constraint(equalTo: view.bottomAnchor, constant: 0)
    let constraints = [
        undoView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        undoView.widthAnchor.constraint(equalToConstant: view.bounds.width / 3),
        bottomConstraint,
        undoView.heightAnchor.constraint(equalToConstant: 50)
    ]
    view.addSubview(undoView)
    NSLayoutConstraint.activate(constraints)
    undoView.layoutIfNeeded()

    bottomConstraint.isActive = false
    bottomConstraint = undoView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor, constant: -58)
    bottomConstraint.isActive = true

    UIView.animate(withDuration: 0.5, delay: 0.2, animations: 
        self.undoView.layoutIfNeeded()
    )

我希望仅在可见视图下方创建视图,然后在底部布局边距上方最多滑动 8 处。然而,这段代码只是让视图在其最终位置“展开”,而不是从底部进入视图。出于某种原因,使用 self.view.layoutIfNeeded() 会使视图从屏幕的左上角飞入。

【问题讨论】:

最有可能是你需要禁用undoView的底部约束。 我这样做对吗?我说bottomConstraint.isActive = false 如果您想使用约束动画,请查看本教程。 youtube.com/watch?v=d1e9bKtOEH8 谢谢你的视频!我意识到我必须创建一个新的约束而不是覆盖现有的约束才能让它工作:) 【参考方案1】:

美好的一天,我通常使用 transform 属性将一个视图从 x 位置移动到 y 部分,请查看此示例。


class ViewController: UIViewController 

    let button : UIButton = 
        let button = UIButton(type: .custom)
        button.setTitle("Button", for: .normal)
        button.backgroundColor = .gray
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    ()

    let customView : UIView = 
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = .red
        return view
    ()

    override func viewDidLoad() 
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        view.addSubview(button)
        view.addSubview(customView)
        NSLayoutConstraint.activate([
            button.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
            button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
            customView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
            customView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
            customView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
            customView.heightAnchor.constraint(equalToConstant: 100)
        ])
    
    override func viewDidAppear(_ animated: Bool) 
        super.viewDidAppear(animated)
        setupAnimationCustomView()
    

    private func setupAnimationCustomView()
        UIView.animate(withDuration: 1, delay: 0 , options: .curveEaseOut, animations: 
            print(self.button.frame.origin.y)
            let translationY = self.view.frame.height - self.button.frame.origin.y - self.button.frame.height - self.customView.frame.height - 8
            self.customView.transform = CGAffineTransform(translationX: 0, y:  translationY * (-1))

        , completion: nil)
    




在动画中,我计算了移动 customView 所需的距离。

【讨论】:

谢谢!我认为使用转换是下一个最好的事情!你知道这个变换是否也会自动更新约束吗?

以上是关于使用 NSLayoutConstraints 在 UIView 上简单滑动动画的主要内容,如果未能解决你的问题,请参考以下文章

使用 NSLayoutConstraints 调整当前视图的大小

使用 NSLayoutConstraints 在 UIView 上简单滑动动画

使用 NSLayoutConstraints 在 UITextView 中将 UILabel 居中

在代码中创建 NSLayoutConstraints

使用 NSLayoutConstraints 时的警告

遇到 NSLayoutConstraints 问题并以编程方式使用自动布局时,UIViews 停留在 (0,0)