在父UIView中移动UIView(使用UIPanGestureRecognizer)

12
我正在使用以下代码来移动一个存在于UIView中的UIImageView。
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {

CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
                                     recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];

}

我想让UIView不会移动到父视图之外。目前,图像视图可以在整个屏幕上移动。

5个回答

12

首先获取您的 UIImageView 的新框架,并使用 CGRectContainsRect() 方法检查它是否完全位于其超级视图中。如果是,则将 UImageView 的框架设置为新框架。

- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {

    CGPoint translation = [recognizer translationInView:self.view];
    CGRect recognizerFrame = recognizer.view.frame;
    recognizerFrame.origin.x += translation.x;
    recognizerFrame.origin.y += translation.y; 

    // Check if UIImageView is completely inside its superView
    if (CGRectContainsRect(self.view.bounds, recognizerFrame)) {
        recognizer.view.frame = recognizerFrame;
    }
    // Else check if UIImageView is vertically and/or horizontally outside of its
    // superView. If yes, then set UImageView's frame accordingly.
    // This is required so that when user pans rapidly then it provides smooth translation.
    else {
        // Check vertically
        if (recognizerFrame.origin.y < self.view.bounds.origin.y) {
            recognizerFrame.origin.y = 0;
        }        
        else if (recognizerFrame.origin.y + recognizerFrame.size.height > self.view.bounds.size.height) {
            recognizerFrame.origin.y = self.view.bounds.size.height - recognizerFrame.size.height;
        }

        // Check horizantally
        if (recognizerFrame.origin.x < self.view.bounds.origin.x) {
            recognizerFrame.origin.x = 0;
        }
        else if (recognizerFrame.origin.x + recognizerFrame.size.width > self.view.bounds.size.width) {
            recognizerFrame.origin.x = self.view.bounds.size.width - recognizerFrame.size.width;
        }
    }

    // Reset translation so that on next pan recognition
    // we get correct translation value
    [recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
}

确保您传递superViewboundsUIImageViewframe,以便两个CGRects处于相同的坐标系中。


除了这一点,一切都很好:你不知道recognizer.view的superview是self.view,如果用户在superview的边界之外快速移动,你会看到recognizer的框架在superview的中间冻结的丑陋效果。最后,如果这个用户继续移动,视图将继续移动,而不再在用户的手指下。总的来说,你可以做得更好。 - micantox
@micantox 我同意你的一些观点,并更新了我的回答。关于superView,我知道self.view 是imageView的superView,因为他自己在代码中使用self.view作为superView。 - Geek
@IconicDigital,请查看我的更新答案,以确保在所有情况下都有正确的翻译效果。 - Geek
我不确定我缺少什么,但是从我的角度来看,UIPanGestureRecognizer没有“frame”属性...所以recognizer.frame无法工作。我可以使用recognizer.view.frame,但是将recognizer.view.frame设置为recognizerFrame似乎不会做任何事情,因为我只是将相同的值分配回自身。我尝试了下面的另一种方法,对我很有效,但仍然对此很好奇。如果有人能提供建议,我将不胜感激,谢谢。 - Reid
@ReidBelton,你必须使用recognizer.view.frame是正确的。它没有移动的原因可能是:“你根本没有改变它的值”或者“你正在改变不是你想拖动的视图的框架”。 - Geek

8

尝试使用:

- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer 
{
    if (gesture.state==UIGestureRecognizerStateChanged || gesture.state == UIGestureRecognizerStateEnded){
        UIView *superview = recognizer.view.superview;
        CGSize superviewSize = superview.bounds.size;
        CGSize thisSize = recognizer.view.size;
        CGPoint translation = [recognizer translationInView:self.view];
        CGPoint center = CGPointMake(recognizer.view.center.x + translation.x,
                                 recognizer.view.center.y + translation.y);

        CGPoint resetTranslation = CGPointMake(translation.x, translation.y);

        if(center.x - thisSize.width/2 < 0)
            center.x = thisSize.width/2;
        else if (center.x + thisSize.width/2 > superviewSize.width)
            center.x = superviewSize.width-thisSize.width/2;
        else
            resetTranslation.x = 0; //Only reset the horizontal translation if the view *did* translate horizontally

        if(center.y - thisSize.height/2 < 0)
            center.y = thisSize.height/2;
        else if(center.y + thisSize.height/2 > superviewSize.height)
            center.y = superviewSize.height-thisSize.height/2;
        else
            resetTranslation.y = 0; //Only reset the vertical translation if the view *did* translate vertically

        recognizer.view.center = center;
        [recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
    }
}

这样就不会移动超出父视图边界,如果您尝试将其移出边界,它只会“粘”在边缘上!


6

micantox答案的Swift版本

let gesture = UIPanGestureRecognizer(target: self, action: #selector(self.wasDragged(gestureRecognizer:)))
imageView.addGestureRecognizer(gesture)
imageView.isUserInteractionEnabled = true

@objc func wasDragged(gestureRecognizer: UIPanGestureRecognizer) {
if gestureRecognizer.state == UIGestureRecognizerState.changed || gestureRecognizer.state == UIGestureRecognizerState.ended {
   let superview = gestureRecognizer.view?.superview
   let superviewSize = superview?.bounds.size
   let thisSize = gestureRecognizer.view?.frame.size
   let translation = gestureRecognizer.translation(in: self.view)
   var center = CGPoint(x: gestureRecognizer.view!.center.x + translation.x, y: gestureRecognizer.view!.center.y + translation.y)
   var resetTranslation = CGPoint(x: translation.x, y: translation.y)

   if center.x - (thisSize?.width)!/2 < 0 {
       center.x = (thisSize?.width)!/2
       } else if center.x + (thisSize?.width)!/2 > (superviewSize?.width)! {
       center.x = (superviewSize?.width)!-(thisSize?.width)!/2
       } else {
         resetTranslation.x = 0 //Only reset the horizontal translation if the view *did* translate horizontally
       }

   if center.y - (thisSize?.height)!/2 < 0 {
       center.y = (thisSize?.height)!/2
      } else if center.y + (thisSize?.height)!/2 > (superviewSize?.height)! {
       center.y = (superviewSize?.height)!-(thisSize?.height)!/2
      } else {
        resetTranslation.y = 0 //Only reset the vertical translation if the view *did* translate vertically
      }

      gestureRecognizer.view?.center = center
      gestureRecognizer.setTranslation(CGPoint(x: 0, y: 0), in: self.view)
    } 
}

1

如果recognizer.view.frame在其父视图的bounds内,你需要将recognizer.view.center设置为一个新值。使用CGRectContainsRect函数检查recognizer.view.superview.boundsrecognizer.view.frame是否被包含在内。

如果你想让图片视图在其父视图之外移动,直到视图中心点超出父视图的边界,你可以使用UIViewconvertPoint:toView方法检查新的CGPoint是否在父视图的边界内。


0
if (gesture.state==UIGestureRecognizerStateChanged){

CGPoint translation = [recognizer translationInView:self.view];

CGRect rectToCheck=CGRectMake(yourView.frame.origin.x+translation.x,       yourView.frame.origin.y+translation.y, CGRectGetWidth(yourView.frame),     CGRectGetHeight(yourView.frame));

     if(CGRectContainsRect(self.view.bounds,rectToCheck))// check that the rect that is   going to form lies within the bounds of self.view
     {

     yourView.frame=CGRectMake(yourView.frame.origin.x+translation.x,  yourView.frame.origin.y+translation.y, CGRectGetWidth(yourView.frame),  CGRectGetHeight(yourView.frame)); 
     }
     [gesture setTranslation:CGPointZero yourView]; // important to set this 

 }

提示:使用手势状态块来启动、平移和删除。例如:UIGestureRecognizerStateBegan UIGestureRecognizerStateChanged UIGestureRecognizerStateEnded


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接