首页 > 解决方案 > Swift:启用或禁用约束错误

问题描述

我正在一个名为 separatorView 的视图上创建一个手势(在照片中它是中间的黑色视图)。

我使用约束方法和优先级来做到这一点:

-centerConstraint = 这是允许在 X 中水平居中视图的约束,优先级 = 1000

-rightConstant = 此约束将视图链接到右屏幕边缘的零点,优先级 = 999

-GaucheConstant = 此约束将视图链接到左屏幕边缘的零点,优先级 = 998

当我将此视图拖到左侧时,动画会继续拖动。

问题是动画完成后,我想恢复视图并将其拖到左侧现金应用程序中心约束为nil!

我找不到使其通用的解决方案,我可以将视图向右或向左滑动而没有任何问题

我知道问题出在我禁用约束的事实

照片

这是我的代码:

@IBOutlet weak var sep: UIView!

@IBOutlet weak var constantGauche: NSLayoutConstraint!

@IBOutlet weak var constantDroite: NSLayoutConstraint!
@IBOutlet weak var centerConstraint: NSLayoutConstraint!

var startingConstant: CGFloat  = 0.0

var panGesture: UIPanGestureRecognizer?

override func viewDidLoad() {
    super.viewDidLoad()
    panGesture = UIPanGestureRecognizer(target: self, action: #selector(detectPan(recognizer:)))
    panGesture?.delaysTouchesBegan = false
    panGesture?.delaysTouchesEnded = false
    sep.addGestureRecognizer(panGesture!)
}

@objc func detectPan(recognizer: UIPanGestureRecognizer) {

    let translation = recognizer.translation(in: self.view)

    switch recognizer.state {
    case .began:
        self.startingConstant = self.centerConstraint.constant
    case .changed:
        self.centerConstraint.constant = self.startingConstant + translation.x
    case .ended:
        if translation.x > 0 {
            centerConstraint.isActive = false
            constantGauche.isActive = false
            constantDroite.isActive = true
            UIView.animate(withDuration: 0.5) {
                self.view.layoutIfNeeded()
            }
        }else{
            centerConstraint.isActive = false
            constantGauche.isActive = true
            constantDroite.isActive = false
            UIView.animate(withDuration: 0.5) {
                self.view.layoutIfNeeded()
            }
        }
    default:
        break
    }
}

标签: swiftconstraintsgesture

解决方案


是的,当您禁用中心约束时,iOS 会将其从视图的约束中移除并释放它,因为不再有对它的强引用。这@IBOutlet是一个引用,一旦强引用全部消失,weak它就会被设置为。nil因此,下次您访问中心约束时,它会崩溃,因为它已经并且nil隐含用.centerConstraint!

不要禁用约束,而是修改它们的优先级:

  • 将中心约束优先级更改为999作为起始值。如果您尝试在代码中修改所需约束的优先级,则会收到错误消息。
  • 降低priority左侧和中心约束的 将导致sep向右移动。一旦它到达那里,您可以计算中心constant约束的新值,然后将它们的优先级设置回起始值。
  • 降低priority右侧和中心约束的 将导致sep向左移动。一旦它到达那里,您可以计算中心constant约束的新值,然后将它们的优先级设置回起始值。

@objc func detectPan(recognizer: UIPanGestureRecognizer) {

    let translation = recognizer.translation(in: self.view)

    switch recognizer.state {
    case .began:
        self.startingConstant = self.centerConstraint.constant
    case .changed:
        self.centerConstraint.constant = self.startingConstant + translation.x
    case .ended:
        if translation.x > 0 {
            centerConstraint.priority = UILayoutPriority(rawValue: 750)
            constantGauche.priority = UILayoutPriority(rawValue: 750)
        } else {
            centerConstraint.priority = UILayoutPriority(rawValue: 750)
            constantDroite.priority = UILayoutPriority(rawValue: 750)
        }
        UIView.animate(withDuration: 0.5) {
            self.view.layoutIfNeeded()
        }
        print(sep.center.x - view.center.x)
        centerConstraint.constant = sep.center.x - view.center.x
        centerConstraint.priority = UILayoutPriority(rawValue: 999)
        constantGauche.priority = UILayoutPriority(rawValue: 998)
        constantDroite.priority = UILayoutPriority(rawValue: 998)
    default:
        break
    }
}

以下是模拟器中运行的更改:

模拟器中的分隔符图像


推荐阅读