15

我有几个用户应该能够拖放的 UIView。我使用UIPanGestureRecognizer来管理 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];

}

我尝试了一些“解决”问题但导致其他问题的方法:

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

我开始加深对自动布局的理解,但是当我觉得我要寻找的东西应该很简单时,它变得非常复杂;我看到了许多处理执行“重新自动布局”的方法,但我不清楚如何使用它们。

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

任何帮助将不胜感激。

4

2 回答 2

12

我认为,如果您使用自动布局并且想要更改视图的位置,则需要更新视图上的约束,而不是手动设置视图的中心。从描述中听起来您正在设置中心,但是当应用程序接下来布置视图(例如,您拖动另一个视图)时,它会将中心重新设置为自动布局所说的任何内容。

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

要在代码中设置约束,您可以清除移动视图的约束并重新添加它们,或者如果您在 IB 中有视图,您可以将约束拖到代码中以创建插座。查看 removeConstraints 和 addConstraints 方法以在代码中执行此操作。

最后,如果它在没有自动布局的情况下按您的意愿工作,您可以尝试在移动的视图上设置 translatesAutoresizingMaskIntoConstraints = YES,但请注意这可能会导致其他地方发生冲突。

于 2013-04-21T19:19:18.747 回答
7

这一切都可以使用 Interface Builder。这是我用来执行此操作的代码:

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

然后将这些 IBOutlets 连接到 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 重置了视图,但约束会在这里做你需要的!

于 2014-03-19T03:33:08.533 回答