无法使用 UIimageView 激活带有锚点错误的约束

Unable to activate constraint with anchors error with UIimageView

第一次在这里发帖。

所以我一直在尝试制作一个 UIimageView 的动画。到目前为止,我是这样做的。所以图像从屏幕中间移动到顶部。我希望能够制作带有约束的动画。但是在尝试添加一些约束时,我收到此错误“无法使用锚点错误激活约束”。

这是我尝试向 banditLogo imageview 添加一些约束的代码。

        override func viewDidLoad() {
    super.viewDidLoad()
    
    
    
    view.addSubview(banditLogo)
    
    view.translatesAutoresizingMaskIntoConstraints = false // autolayout activation
    
    chooseLabel.alpha = 0
    signInButtonOutlet.alpha = 0
    
    self.banditLogo.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 304).isActive = true
    self.banditLogo.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 94).isActive = true
    self.banditLogo.widthAnchor.constraint(equalToConstant: 224).isActive = true
    self.banditLogo.heightAnchor.constraint(equalToConstant: 289).isActive = true

  }

这里是制作动画的函数。

此函数在 viewDidAppear 中被调用,函数的 animatedImage 变量被引用到 banditLogo UIimageView。 所以当视图屏幕加载时,图像移动到视图的顶部。

func logoAnimate(animatedImage: UIImageView!, animatedLabel: UILabel!) {
        UIView.animate(withDuration: 1.5, delay: 1, options: [.allowAnimatedContent]) {
        animatedImage.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 5).isActive = true
        animatedImage.leftAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leftAnchor, constant: 94).isActive = true

    }   completion: { (true) in
        UIView.animate(withDuration: 0.25) {
            animatedLabel.alpha = 1
      }
      
    }
}

我通过 更改 约束而不是 设置 来为具有约束的视图设置动画。保留静态约束“原样”——即使用 isActive = true。但是那些你想改变的?将它们放在 两个 数组和 activate/deactivte 中。使用 UIView.animate.

像您一样完成动画

例如,假设您希望将 banditLogo 从前 304 位移动到前 5 位,这在我看来就是您想要做的。将 all 其他约束保持原样 - 左侧(您的代码似乎没有更改)、高度和宽度。现在,创建两个数组:

var start = [NSLayoutConstraint]()
var finish = [NSLayoutConstraint]()

添加变化的约束。请注意,我没有将它们设置为活动状态:

start.append(banditLogo.topAnchor.constraint(equalTo: safeAreaView.topAnchor, constant: 305))
finish.append(banditLogo.topAnchor.constraint(equalTo: safeAreaView.topAnchor, constant: 5))

根据需要在 viewDidLoad 或任何其他视图控制器方法中初始化:

NSLayoutConstraint.activate(start)

最后,当您想要制作动画时,deactivate/activate 并告诉视图显示动画:

NSLayoutConstraint.deactivate(start)
NSLayoutConstraint.activate(finish)
UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() }

最后一篇评论,无意冒犯。

我觉得你发布的代码中有些东西很乱。创建一个移动单个视图的函数应该直接处理视图恕我直言,而不是将视图传递给它。也许您正在尝试以这种方式移动多个视图 - 在这种情况下这是很好的代码 - 但您的问题中没有任何暗示。可以在函数中执行动画 - 这样您就可以在需要时调用它。我一直这样做是为了这样的事情 - 将工具覆盖层滑入和滑出。但是,如果您对单个视图执行此操作,只需直接解决它。代码对其他编码人员更易读。

此外,我对 start 的偏好在 viewDidLoad 中,除非 VC 是导航堆栈的一部分。但在那种情况下,不要只是使用viewDidAppear,在viewDidDisappear.

中设置回start

编辑:查看评论,我假设已经在每个需要的视图上正确使用translatesAutoresizingMaskIntoConstraints = false .

您可能会发现创建一个 class 级 属性 来保存图像视图的顶部约束,然后在您想要移动它时更改该约束的 .constant 值会更容易。

这是一个简单的示例 - 点击视图上的任意位置将使图像视图上下移动:

class AnimLogoViewController: UIViewController {

    let banditLogo = UIImageView()
    
    // we'll change this constraint's .constant to change the image view's position
    var logoTopConstraint: NSLayoutConstraint!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        if let img = UIImage(systemName: "person.fill") {
            banditLogo.image = img
        }
        
        view.addSubview(banditLogo)
        
        // I assume this was a typo... you want to set it on the image view, not the controller's view
        //view.translatesAutoresizingMaskIntoConstraints = false // autolayout activation
        banditLogo.translatesAutoresizingMaskIntoConstraints = false // autolayout activation

        // create the image view's top constraint
        logoTopConstraint = banditLogo.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 304)
        // activate it
        logoTopConstraint.isActive = true
        
        // non-changing constraints
        self.banditLogo.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 94).isActive = true
        self.banditLogo.widthAnchor.constraint(equalToConstant: 224).isActive = true
        self.banditLogo.heightAnchor.constraint(equalToConstant: 289).isActive = true

        // animate the logo when you tap the view
        let t = UITapGestureRecognizer(target: self, action: #selector(self.didTap(_:)))
        view.addGestureRecognizer(t)
    }
    
    @objc func didTap(_ g: UITapGestureRecognizer) -> Void {
        // if the logo image view is at the top, animate it down
        //  else, animate it up
        if logoTopConstraint.constant == 5.0 {
            logoTopConstraint.constant = 304.0
        } else {
            logoTopConstraint.constant = 5.0
        }
        UIView.animate(withDuration: 1.5, animations: {
            self.view.layoutIfNeeded()
        })
    }

}