iOS >>拖动视图跳回原始位置>>自动布局与UIPanGestureRecognizer问题结合

我有几个UIViews,用户应该能够拖放。 我使用UIPanGestureRecognizer来pipe理d&d操作(请参阅下面的代码)。 d&d动作工作正常,但是当我开始拖动另一个UIView时,我刚刚掉落的那个就跳回原来的位置。

- (void)handlePan:(UIPanGestureRecognizer *)recognizer { CGPoint translation = [recognizer translationInView:self.view]; switch (recognizer.state) { case UIGestureRecognizerStateBegan: for (UIView* checkView in dragAndDropImageViewsArray) { if (checkView == recognizer.view) { [checkView.superview bringSubviewToFront:checkView]; //this is done to make sure the currently dragged object is the top one } } break; case UIGestureRecognizerStateChanged: recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x, recognizer.view.center.y + translation.y); break; case UIGestureRecognizerStateEnded: NSLog(@"UIGestureRecognizerStateEnded"); break; default: break; } [recognizer setTranslation:CGPointMake(0, 0) inView:self.view]; } 

我尝试了几个“解决”问题的方法,但却造成了其他问题:

  • 取消自动布局 :完全解决它,但现在我必须开始计算和pipe理不同设备和方向的对象位置和大小。
  • 使用layer.zPosition而不是bringSubviewToFront :它使对象显示在其他对象之上,同时显然避免了“跳回”,但不允许我改变不同的可拖动对象之间的层次结构。

我开始加深对自动布局的理解,但是在我看来,我所寻找的应该是非常简单的; 我看到了很多处理“重新自动布局”的方法,但我不清楚如何使用它们。

这里有一个简单的解决scheme吗? 比如调用一个覆盖IB自动布局约束的方法,并根据UIView的新位置重新定义它们?

任何援助将非常musch赞赏。

我认为,如果您使用的是自动布局,而您想要更改视图的位置,则需要更新视图上的约束,而不是手动设置视图的中心。 从描述中可以看出,您正在设置中心,但是当应用下一步布置视图时(例如,拖动另一个视图),会将中心重新设置为自动布局应该显示的内容。

我不确定你的应用的其他部分是什么样的,但是你可能能够find附近的视图并添加约束,或者你可能更喜欢更新拖动视图的约束,并设置前导空间和顶部空间手动到超视图。 如果你有一个方便的集合,你也可以清除所有的约束,然后重新添加它们,因为你想保持填充在视图之间。

要在代码中设置约束,您可以清除已移动视图的约束并重新添加它们,或者如果您在IB中具有视图,则可以将约束拖动到代码中以创build出口。 查看removeConstraints和addConstraints方法在代码中执行。

最后,如果它的工作方式没有自动布局,你可以尝试在移动的视图上设置translatesAutoresizingMaskIntoConstraints = YES,但要注意可能导致其他地方的冲突。

这是使用Interface Builder所有可能的。 这是我用来做这个的代码:

 @property (weak,nonatomic) IBOutlet NSLayoutConstraint *buttonXConstraint; @property (weak,nonatomic) IBOutlet NSLayoutConstraint *buttonYConstraint; 

然后将这些IBOutlet连接到Interface Builder中的水平约束(X位置)和垂直约束(Y位置)。 确保约束连接到基本视图,而不是最接近的视图。

挂起一个平移手势,然后使用下面的代码拖动你的对象:

 - (IBAction)panPlayButton:(UIPanGestureRecognizer *)sender { if(sender.state == UIGestureRecognizerStateBegan){ } else if(sender.state == UIGestureRecognizerStateChanged){ CGPoint translation = [sender translationInView:self.view]; //Update the constraint's constant self.buttonXConstraint.constant += translation.x; self.buttonYConstraint.constant += translation.y; // Assign the frame's position only for checking it's fully on the screen CGRect recognizerFrame = sender.view.frame; recognizerFrame.origin.x = self.buttonXConstraint.constant; recognizerFrame.origin.y = self.buttonYConstraint.constant; // Check if UIImageView is completely inside its superView if(!CGRectContainsRect(self.view.bounds, recognizerFrame)) { if (self.buttonYConstraint.constant < CGRectGetMinY(self.view.bounds)) { self.buttonYConstraint.constant = 0; } else if (self.buttonYConstraint.constant + CGRectGetHeight(recognizerFrame) > CGRectGetHeight(self.view.bounds)) { self.buttonYConstraint.constant = CGRectGetHeight(self.view.bounds) - CGRectGetHeight(recognizerFrame); } if (self.buttonXConstraint.constant < CGRectGetMinX(self.view.bounds)) { self.buttonXConstraint.constant = 0; } else if (self.buttonXConstraint.constant + CGRectGetWidth(recognizerFrame) > CGRectGetWidth(self.view.bounds)) { self.buttonXConstraint.constant = CGRectGetWidth(self.view.bounds) - CGRectGetWidth(recognizerFrame); } } //Layout the View [self.view layoutIfNeeded]; } else if(sender.state == UIGestureRecognizerStateEnded){ } [sender setTranslation:CGPointMake(0, 0) inView:self.view]; } 

我在那里添加了代码来检查框架,并确保它不会超出视图。 如果你想让物体部分离开屏幕,可以随意取出。

这花了一点时间让我意识到,这是使用AutoLayout重置视图,但约束将做你所需要的!

Interesting Posts