如何在Swift中更新锚点约束

3
我希望在iOS上创建一个类似于Android的菜单。我正在使用布局约束来设置约束条件。当我尝试在按钮点击时更新图像的左侧约束时(它应该动画到单击的按钮位置),我遇到了问题。有人能帮我吗?它应该支持横向和纵向。 我不想使用第三方代码,也不想使用NSLayoutconstraint。

Landscape image Potrait Image

这是我的代码。

class MenuViewController: UIViewController {
            var buttons: [UIButton] = []
            var imageView : UIImageView!

            override func viewDidLoad() {
                super.viewDidLoad()
            }

            override func viewDidAppear(_ animated: Bool) {
                super.viewDidAppear(animated)
                addMenuItems()
            }

            func addMenuItems() {

                for _ in 0...4 {
                    let button : UIButton = UIButton()
                    self.view.addSubview(button)
                    button.backgroundColor = UIColor.darkGray
                    button.addTarget(self, action: #selector(didSelectedButton(_:)), for: .touchUpInside)
                    self.buttons.append(button)

                }

                for (index, button) in buttons.enumerated() {

                    button.setTitle(" \(index)", for: .normal)
                    if index == 0 {
                        button.translatesAutoresizingMaskIntoConstraints = false
                        button.leftAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leftAnchor, constant: 0).isActive = true
                        button.widthAnchor.constraint(greaterThanOrEqualToConstant: 1).isActive = true
                        button.heightAnchor.constraint(equalToConstant: 50).isActive = true
                        button.topAnchor.constraint(equalTo: self.view.topAnchor, constant:200).isActive = true

                        self.imageView = UIImageView()
                        self.view.addSubview(self.imageView)
                        self.imageView.backgroundColor = UIColor.red

                        self.imageView.translatesAutoresizingMaskIntoConstraints = false
                        self.imageView.leftAnchor.constraint(equalTo: button.leftAnchor, constant: 0).isActive = true
                        self.imageView.widthAnchor.constraint(equalTo: button.widthAnchor, multiplier: 1).isActive = true
                        self.imageView.heightAnchor.constraint(equalToConstant: 4).isActive = true
                        self.imageView.topAnchor.constraint(equalTo: self.view.topAnchor, constant:250).isActive = true

                    }
                    else {

                        let preButton = buttons\[index - 1\]
                        button.translatesAutoresizingMaskIntoConstraints = false
                        button.leftAnchor.constraint(equalTo: preButton.rightAnchor, constant: 0).isActive = true
                        button.widthAnchor.constraint(equalTo: preButton.widthAnchor, multiplier: 1).isActive = true
                        button.heightAnchor.constraint(equalToConstant: 50).isActive = true
                        button.topAnchor.constraint(equalTo: self.view.topAnchor, constant:200).isActive = true
                        if index == self.buttons.count - 1 {
                            button.rightAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.rightAnchor, constant: 0).isActive = true
                        }
                    }

                }

            }

            @objc func didSelectedButton(_ button:UIButton) {
                UIView.animate(withDuration: 1, animations: {
                    self.imageView.leftAnchor.constraint(equalTo: button.leftAnchor).isActive = true
                    self.imageView.layoutIfNeeded()
                }, completion: nil)
            }

        }
1个回答

10

使用锚点可以创建NSLayoutConstraint。在创建新的约束时,需要停用先前的约束。

将此属性添加到您的MenuViewController中:

var imageLeftConstraint: NSLayoutConstraint?

在创建约束时首次设置它:

imageLeftConstraint = self.imageView.leftAnchor.constraint(equalTo: button.leftAnchor, constant: 0)
imageLeftConstraint?.isActive = true

然后在添加新的限制之前,使用它来停用先前的限制:

@objc func didSelectedButton(_ button:UIButton) {
    imageLeftConstraint?.isActive = false
    imageLeftConstraint = self.imageView.leftAnchor.constraint(equalTo: button.leftAnchor)
    imageLeftConstraint?.isActive = true
    UIView.animate(withDuration: 1, animations: {
        self.view.layoutIfNeeded()
    }, completion: nil)
}

注意:您需要在imageView的超级视图(即self.view)上调用layoutIfNeeded(),因为buttonimageView之间的约束将添加到它们的共同祖先(self.view )。


我已经做了这个,还有其他方法吗?感谢vacawama和vikas。 - Damodar
你对这种方式有什么反对意见? - vacawama
没事了,只是需要所有的解决方案。无论如何感谢您的支持,我已经找到了解决方案。 - Damodar
.isActive = false” 实际上是做什么的?它会将其保留在长列表中还是移动到忽略的队列末尾(就像 UNIX 中的调度程序一样)?因为随着时间的推移,这些已停用的约束可能会累积并减慢速度,如果不进行垃圾回收(而且我不知道为什么它们会被垃圾回收,因为它们可以重新激活)。我想在每次有人编辑文本字段时更改约束。这可能不是一个频繁发生的问题,所以不会有问题,而且我想如果您想调整约束,NSConstraint 类允许修改 .constant - clearlight
将一个约束条件设置为false会将其从视图层次结构中移除(意味着减少一个保留它的对象)。如果您没有另一个强指针指向该约束条件,那么它将被释放。在这个例子中,约束条件由var imageLeftConstraint: NSLayoutConstraint?属性持有,但当它的指针被新创建的约束条件重写时,它将没有强引用,并被释放。 - vacawama

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接