Измените ограничения макета Automati c, проведя пальцем - PullRequest
0 голосов
/ 28 января 2020

На экране две картинки, на них программно установлены ограничения. При пролистывании влево картинки меняются и становятся такими, какими они должны быть. Если после этого проведите пальцем вправо, то ничего не произойдет и картинки останутся на своих местах. Вот код реализации.

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),
            ])

    }

Когда я делаю свайп вправо, он выдает такие ошибки

Попытается восстановить, нарушив ограничение (active, names: ' | ': UIView: 0x10080e7a0)>

Создайте символическую c точку останова в UIViewAlertForUnsatisfiableConstraints, чтобы перехватить это в отладчике. Методы в категории UIConstraintBasedLayoutDebugging в UIView, перечисленные в, также могут быть полезны. Неустранимая ошибка: неожиданно найденный ноль при неявном развертывании необязательного значения 2020-01-28 15: 09: 59.920450 + 0200 ThemeGame [27748: 2857822] Неустранимая ошибка: неожиданно обнаруженный ноль при неявном развертывании необязательного значения

1 Ответ

1 голос
/ 28 января 2020

Поскольку вы опубликовали несколько очень похожих вопросов, я настоятельно рекомендую потратить некоторое время на изучение работы ограничений и автоматической компоновки.

Кадры 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)

        }
    }

}
...