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

Oha*_*gev 13 drag-and-drop uigesturerecognizer ios subviews autolayout

我有几个用户应该能够拖放的UIViews.我使用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];

}
Run Code Online (Sandbox Code Playgroud)

我尝试了几个"解决"问题但引起其他问题的事情:

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

我开始加深对Auto Layout的理解,但是在我看来,我正在寻找的东西应该非常简单; 我看到很多方法都涉及执行"重新自动布局",但我不清楚如何使用它们.

这里有简单的解决方案吗?比如调用一个覆盖IB Auto-Layout约束的方法并根据UIView的新位置重新定义它们?

任何援助都会非常受欢迎.

Jam*_*mes 11

我认为如果您使用autolayout并且想要更改视图的位置,则需要更新视图上的约束,而不是手动设置视图的中心.从描述中可以看出你正在设置中心,但是当应用程序接下来放置视图时(例如你拖动另一个),它会将中心重新设置为自动布局应该是什么.

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

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

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


jka*_*ter 6

使用Interface Builder可以实现这一切.以下是我用来执行此操作的代码:

@property (weak,nonatomic) IBOutlet NSLayoutConstraint *buttonXConstraint;
@property (weak,nonatomic) IBOutlet NSLayoutConstraint *buttonYConstraint;
Run Code Online (Sandbox Code Playgroud)

然后将这些IBOutlet连接到Interface Builder中的Horizo​​ntal Constraint(X Position)和Vertical Constraint(Y Position).确保将约束连接到基本视图而不是它最近的视图.

连接平移手势,然后使用以下代码拖动您的对象:

- (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];
}
Run Code Online (Sandbox Code Playgroud)

我在那里添加了代码来检查框架,并确保它不会超出视图范围.如果您想让对象部分脱离屏幕,请随意将其取出.

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