UIButton帧如果被淘汰则不会改变

时间:2018-05-29 07:59:52

标签: ios swift autolayout uipangesturerecognizer

Here is an image of a simple APP I am trying to make

App有一个用于中心紫色按钮的平移手势识别器,如果它与4个橙色按钮中的任何一个相交,则移动按钮,紫色按钮动画并在其相交的按钮边界内移动,否则它会动画回到初始起始位置即中心。

第一次当我平移紫色按钮时,按钮的框架会更新,但是如果我第二次尝试按钮的框架保持不变(当它在视图中心时的值) )。

我猜这是与我错过的自动布局有关的东西,因为如果我删除中心紫色按钮上的约束,如果我平移,框架每次都会正确更新。

任何人都可以解释在使用约束设置动画时我必须记住的内容

这是我处理Pan手势的代码:

@objc func handleCenterRectPan(_ pannedView: UIPanGestureRecognizer) {

        let fallBackAnimation = UIViewPropertyAnimator(duration: 0.3, dampingRatio: 0.5) {
                if self.button1.frame.intersects(self.centerRect.frame) {
                    self.centerRect.center = self.button1.center
                } else if self.button2.frame.contains(self.centerRect.frame) {
                    self.centerRect.center = self.button2.center
                } else if self.button3.frame.contains(self.centerRect.frame) {
                    self.centerRect.center = self.button3.center
                } else if self.button4.frame.contains(self.centerRect.frame) {
                    self.centerRect.center = self.button4.center
                } else {
                    // no intersection move to original position
                    self.centerRect.frame = OGValues.oGCenter
                }
        }

        switch pannedView.state {
        case .began:
            self.centerRect.center = pannedView.location(in: self.view)
        case .changed:
            print("Changed")
            self.centerRect.center = pannedView.location(in: self.view)
        case .ended, .cancelled, .failed :
            print("Ended")
            fallBackAnimation.startAnimation();
            //snapTheRectangle()
        default:
            break
        }
    }

1 个答案:

答案 0 :(得分:0)

首先,如果您的目标是顺利移动您的观点,则不应该给予限制。如果你无法抵抗约束,你必须不断更新约束而不是帧(中心), 在您的代码中,我假设您已经给出了紫色按钮中心约束,然后您在使用平移手势进行用户拖动时更改按钮的中心。问题是您给出的约束仍处于活动状态,并且一旦布局需要更新,它就会尝试将其设置回来。

所以你可以做的是

不要给出约束,因为当用户拖动时需要自由移动

OR

为约束创建IBoutlet,并在用户拖动时将.isActive设置为false,如果它不在任何其他按钮内并且更新UpdateLayoutIfNeeded,则将其设置为true,这样它将返回到原始位置。 (好方法)

@IBOutlet var horizontalConstraints: NSLayoutConstraint!            
@IBOutlet var verticalConstraints: NSLayoutConstraint!

//make active false as the user is dragging the view
horizontalConstraints.isActive = false
verticalConstraints.isActive = false
self.view.layoutIfNeeded()

//make it true again if its not inside any of the other views 
horizontalConstraints.isActive = true
verticalConstraints.isActive = true
self.view.layoutIfNeeded()

OR

当用户移动视图时更新水平和垂直约束的constraints.constants(不是一个好方法),如果它不在任何其他视图中,则再次将其设为零

//make it true again if its not inside any of the other views 
horizontalConstraints.constant = change in horizontal direction
verticalConstraints..constant =  change in vertical direction
self.view.layoutIfNeeded()

编辑正如您所说,设置isActive = false后约束为零,因为 实际做的是添加和删除这些约束,如Apple doc所说

  

激活或取消激活约束会在视图上调用addConstraint( :)和removeConstraint( :),该视图是此约束管理的项目的最近共同祖先。使用此属性而不是直接调用addConstraint( :)或removeConstraint( :)。

因此,制定约束强引用确实可以解决问题,但我认为设置对IBOutelet的强引用并不是一个好主意,以编程方式添加和删除约束更好。看看这个问题解除分配约束