【问题标题】:Moving UIView within Parent UIView (UIPanGestureRecognizer)在父 UIView 中移动 UIView (UIPanGestureRecognizer)
【发布时间】:2013-06-21 12:02:37
【问题描述】:

我正在使用以下代码来移动 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 不会移动到父视图之外。此刻图像视图能够在整个屏幕上移动。

【问题讨论】:

    标签: ios objective-c uiview uiimageview


    【解决方案1】:

    首先获取UIImageView 的新框架,并使用CGRectContainsRect() 方法检查它是否完全在其superView 内。如果是,则将UImageView's 框架设置为新框架。

    - (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];
    }
    

    确保您传递了 superView 的 boundsUIImageViewframe,以便 CGRects 位于同一坐标系中。

    【讨论】:

    • 这一切都很好,除了:你不知道识别器.view 的超级视图是 self.view 并且如果用户非常快速地平移到超级视图的范围之外,你会得到丑陋的效果识别器的帧冻结在超级视图边界的中间。最后,如果该用户继续平移,则视图将继续平移而不再处于用户的手指之下。总而言之,你可以做得更好。
    • @micantox 我同意你的一些观点并更新了我的答案。对于superView,我知道self.view是imageView的superView,因为他自己在自己的代码中使用了self.view作为superView。
    • @IconicDigital 看看我更新的答案,在所有情况下都有正确的翻译效果。
    • 我不确定我错过了什么,但 UIPanGestureRecognizer 没有我所在位置的“框架”属性......所以识别器框架不起作用。我可以使用recognizer.view.frame,但是将recognizer.view.frame 设置为recognizerFrame 似乎不会做任何事情,因为我只是将相同的值分配回自身。我在下面尝试了一种不同的方法,它对我很有效,但仍然对这个方法很好奇。如果有人可以提供建议,我将不胜感激,谢谢。
    • @ReidBelton 您必须使用recognizer.view.frame 是正确的。它没有移动的原因可能是“你根本没有改变它的值”或“你改变了视图框架而不是你想要拖动的东西”。
    【解决方案2】:

    尝试:

    - (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];
        }
    }
    

    这样它就永远不会移出父视图边界,如果你试图将它移出边界,它只会“粘”在边缘!

    【讨论】:

      【解决方案3】:

      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)
          } 
      }
      

      【讨论】:

        【解决方案4】:

        只有当 frame 位于其父视图的 bounds 内时,您才必须将 recognizer.view.center 设置为新值。在recognizer.view.superview.boundsrecognizer.view.frame 上使用CGRectContainsRect 来验证它们是否被包含。

        如果要允许图像视图移动到其父视图之外直到视图的中心点超出父视图的边界,可以使用UIViewconvertPoint:toView 方法并验证新的CGPoint不在你父母的范围内。

        【讨论】:

          【解决方案5】:
          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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-06-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多