首页 > 解决方案 > 通过滑动更改自动布局限制

问题描述

屏幕上有两张图片,它们是以编程方式设置的限制。在向左滑动时,图片会改变大小并变成应有的样子。如果在那之后,向右滑动,那么什么都不会发生,图片会留在原处。这是实现代码。

func Swipe() {
        let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
        swipeLeft.direction = .left
        self.view.addGestureRecognizer(swipeLeft)

        let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
        swipeRight.direction = .right
        self.view.addGestureRecognizer(swipeRight)
    }

    @objc func handleGesture(gesture: UISwipeGestureRecognizer) -> Void {
        if gesture.direction == .right {


            UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations:{

                self.setupLayoutImageOne()
            }, completion: nil)
             self.view.layoutIfNeeded()

        } else if gesture.direction == .left {


            UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations:{
                self.setupLayoutImageTwo()

            }, completion: nil)
            self.view.layoutIfNeeded()
        }
    }


    func setupLayoutImageOne()
    {

       imageOne.translatesAutoresizingMaskIntoConstraints = false
       imageTwo.translatesAutoresizingMaskIntoConstraints = false

        let layoutGuide = view

        NSLayoutConstraint.activate([


            imageOne.topAnchor.constraint(equalTo: layoutGuide!.topAnchor),
            imageOne.leadingAnchor.constraint(equalTo: layoutGuide!.leadingAnchor),
            imageOne.trailingAnchor.constraint(equalTo: layoutGuide!.trailingAnchor,constant: 170) ,
            imageOne.bottomAnchor.constraint(equalTo: layoutGuide!.bottomAnchor,constant: 290),


           imageTwo.bottomAnchor.constraint(equalTo: layoutGuide!.bottomAnchor,constant: 530),
           imageTwo.leadingAnchor.constraint(equalTo: layoutGuide!.leadingAnchor,constant: 200),
           imageTwo.trailingAnchor.constraint(equalTo: layoutGuide!.trailingAnchor,constant: 200),
           imageTwo.topAnchor.constraint(equalTo: layoutGuide!.topAnchor,constant: 800),

            ])

    }
    func setupLayoutImageTwo()
    {

       imageOne.translatesAutoresizingMaskIntoConstraints = false
       imageTwo.translatesAutoresizingMaskIntoConstraints = false

        let layoutGuide = view

        NSLayoutConstraint.activate([


           imageOne.topAnchor.constraint(equalTo: layoutGuide!.topAnchor),
           imageOne.leadingAnchor.constraint(equalTo: layoutGuide!.leadingAnchor),
           imageOne.trailingAnchor.constraint(equalTo: layoutGuide!.trailingAnchor,constant: 299) ,
           imageOne.bottomAnchor.constraint(equalTo: layoutGuide!.bottomAnchor,constant: 570),


           imageTwo.bottomAnchor.constraint(equalTo: layoutGuide!.bottomAnchor),
           imageTwo.leadingAnchor.constraint(equalTo: layoutGuide!.leadingAnchor),
          imageTwo.trailingAnchor.constraint(equalTo: layoutGuide!.trailingAnchor),
           imageTwo.topAnchor.constraint(equalTo: layoutGuide!.topAnchor),
            ])

    }

当我向右滑动时,它会给出这样的错误

将尝试通过打破约束来恢复(活动,名称:'|':UIView:0x10080e7a0)>

在 UIViewAlertForUnsatisfiableConstraints 创建一个符号断点以在调试器中捕获它。中列出的 UIView 上的 UIConstraintBasedLayoutDebugging 类别中的方法也可能会有所帮助。致命错误:在隐式展开可选值时意外发现 nil 2020-01-28 15:09:59.920450+0200 ThemeGame[27748:2857822] 致命错误:在隐式展开可选值时意外发现 nil

标签: iosswiftanimationresizeconstraints

解决方案


由于您已经发布了几个非常相似的问题,我强烈建议您花一些时间了解约束和自动布局的工作原理。

imageView 框架看起来很奇怪,因为这条线(例如):

imageOne.bottomAnchor.constraint(equalTo: layoutGuide!.bottomAnchor,constant: 290)

将 imageView 的底部放置在视图底部下方290 点处,因此 290 点(像素)将“离屏”。

但是,这是基于您发布的代码的一种方法。我们为每个 imageView 定义其“向左滑动”位置/大小和“向右滑动”位置/大小的约束。我们将这些约束存储在数组中,然后我们可以根据需要激活/停用:

class SwipeViewController: UIViewController {

    let imageOne: UIImageView = {
        let v = UIImageView()
        v.backgroundColor = .red
        return v
    }()

    let imageTwo: UIImageView = {
        let v = UIImageView()
        v.backgroundColor = .green
        return v
    }()

    // imageOne constraints when swiping Left
    var imageOneLeftConstraints: [NSLayoutConstraint] = [NSLayoutConstraint]()
    // imageOne constraints when swiping Right
    var imageOneRightConstraints: [NSLayoutConstraint] = [NSLayoutConstraint]()
    // imageTwo constraints when swiping Left
    var imageTwoLeftConstraints: [NSLayoutConstraint] = [NSLayoutConstraint]()
    // imageTwo constraints when swiping Right
    var imageTwoRightConstraints: [NSLayoutConstraint] = [NSLayoutConstraint]()

    override func viewDidLoad() {
        super.viewDidLoad()

        imageOne.translatesAutoresizingMaskIntoConstraints = false
        imageTwo.translatesAutoresizingMaskIntoConstraints = false

        view.addSubview(imageOne)
        view.addSubview(imageTwo)

        guard let layoutGuide = view else { fatalError("this should not fail") }

        // local constraint var to reuse
        var c: NSLayoutConstraint


        // define constraints for imageOne when swiping left
        c = imageOne.topAnchor.constraint(equalTo: layoutGuide.topAnchor)
        imageOneLeftConstraints.append(c)
        c = imageOne.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor)
        imageOneLeftConstraints.append(c)
        c = imageOne.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor,constant: 170)
        imageOneLeftConstraints.append(c)
        c = imageOne.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor,constant: 290)
        imageOneLeftConstraints.append(c)

        // define constraints for imageTwo when swiping left
        c = imageTwo.topAnchor.constraint(equalTo: layoutGuide.topAnchor,constant: 800)
        imageTwoLeftConstraints.append(c)
        c = imageTwo.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor,constant: 200)
        imageTwoLeftConstraints.append(c)
        c = imageTwo.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor,constant: 530)
        imageTwoLeftConstraints.append(c)
        c = imageTwo.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor,constant: 200)
        imageTwoLeftConstraints.append(c)


        // define constraints for imageOne when swiping right
        c = imageOne.topAnchor.constraint(equalTo: layoutGuide.topAnchor)
        imageOneRightConstraints.append(c)
        c = imageOne.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor)
        imageOneRightConstraints.append(c)
        c = imageOne.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor,constant: 299)
        imageOneRightConstraints.append(c)
        c = imageOne.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor,constant: 570)
        imageOneRightConstraints.append(c)

        // define constraints for imageTwo when swiping right
        c = imageTwo.topAnchor.constraint(equalTo: layoutGuide.topAnchor)
        imageTwoRightConstraints.append(c)
        c = imageTwo.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor)
        imageTwoRightConstraints.append(c)
        c = imageTwo.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor)
        imageTwoRightConstraints.append(c)
        c = imageTwo.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor)
        imageTwoRightConstraints.append(c)

        // start with imageViews at "swiped left" positions
        NSLayoutConstraint.activate(imageOneLeftConstraints + imageTwoLeftConstraints)

        setupSwipe()
    }

    func setupSwipe() {
        let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
        swipeLeft.direction = .left
        self.view.addGestureRecognizer(swipeLeft)

        let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(handleGesture))
        swipeRight.direction = .right
        self.view.addGestureRecognizer(swipeRight)
    }

    @objc func handleGesture(gesture: UISwipeGestureRecognizer) -> Void {
        if gesture.direction == .right {

            NSLayoutConstraint.deactivate(imageOneLeftConstraints + imageTwoLeftConstraints)
            NSLayoutConstraint.activate(imageOneRightConstraints + imageTwoRightConstraints)

            UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations:{
                self.view.layoutIfNeeded()
            }, completion: nil)

        } else if gesture.direction == .left {

            NSLayoutConstraint.deactivate(imageOneRightConstraints + imageTwoRightConstraints)
            NSLayoutConstraint.activate(imageOneLeftConstraints + imageTwoLeftConstraints)

            UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations:{
                self.view.layoutIfNeeded()
            }, completion: nil)

        }
    }

}

推荐阅读