在 iOS 中制作一个可拖动的 UIView 捕捉到边缘

Posted

技术标签:

【中文标题】在 iOS 中制作一个可拖动的 UIView 捕捉到边缘【英文标题】:Making a draggable UIView that snaps to edges in iOS 【发布时间】:2014-07-28 15:19:30 【问题描述】:

我正在尝试制作一个可以在屏幕上拖动的 UIView,并且在释放时会捕捉到最近的边缘。

我已经解决了拖动问题 - 我正在使用 UILongPressGestureRecognizer,当它的状态结束时,我正在调用以下方法,其中 point 是 longPressGestureRecognizer 的 locationInView,rect 是包含手势识别器和可拖动的 UIView。此方法返回一个 CGPoint,然后我将其设置为可拖动 UIView 的中心。

- (CGPoint)closestPointForPoint:(CGPoint)point toSnapToInRect:(CGRect)rect 

CGPoint closestPoint = point;

/// Left/Right

if ((point.x - rect.origin.x) > (rect.size.width - point.x)) 

    /// Point is closer to right side of frame, update the closestPoint's x.

    closestPoint.x = rect.size.width - (self.draggableView.frame.size.width / 2) - draggableViewMargin;

else 
    /// Point is closer to left side of frame, update the closestPoint's x.
    closestPoint.x = rect.origin.x + (self.draggableView.frame.size.width / 2) + draggableViewMargin;



/// Top/Bottom

if ((point.y - rect.origin.y) > (rect.size.height - point.y)) 
    /// Point is closer to top of frame, update the closestPoint's y.

    closestPoint.y = rect.size.height - (self.draggableView.frame.size.height / 2) - draggableViewMargin;

else 

    /// Point is closer to bottom of frame, update the closestPoint's y.
    closestPoint.y = rect.origin.y + (self.draggableView.frame.size.height / 2) + draggableViewMargin;



return closestPoint;

这可行,只是当我放开视图时,它会捕捉到最近的角落。这很好,但不是我想要的。我希望它捕捉到最近的边缘,例如,如果我在它的点为 x: 50 y:100 时放开视图(在 1136 x 640 的超级视图中),我希望它捕捉到左侧(如x 值更小)但向下 100 像素而不是角落。

有人可以告诉我怎么做吗?

谢谢

【问题讨论】:

任何答案对你有用吗? 【参考方案1】:

你的问题是你在寻找是向左还是向右,以及是向上还是向下。您正在寻找的是一种算法来决定捕捉右、左、上或下。

这是我的解决方案:

//put all of the distances between the point and rect edges in an array.
NSArray *values = @[@(point.x - rect.origin.x), @(rect.size.width - point.x), @(point.y - rect.origin.y), @(rect.size.height - point.y)];

//Find the smallest distance.
NSNumber *minimumValue = [NSNumber numberWithInteger:NSIntegerMax];
for(NSNumber *value in values)
    if([value intValue] < [minimumValue intValue])
        minimumValue = value;
    


if([minimumValue intValue] == point.x - rect.origin.x)
    //snap to the left

if([minimumValue intValue] == rect.size.width - point.x)
    //snap to the right

if([minimumValue intValue] == point.y - rect.origin.y)
    //snap to the top

if([minimumValue intValue] == rect.size.height - point.y)
    //snap to the bottom

它将所有值(上边距、右边距...)放在一个数组中,并遍历它们以找到最小值。您可以编写 if 语句的实现。我已经为你评论了每一个。我希望这能够帮到你。

编辑:

我更新了代码并修复了一些错误。当我测试它时,它对我有用。

【讨论】:

嗨,我试过了,但遗憾的是它不起作用 - 它往往不满足任何条件或只满足最后一个条件(我相信你有错字;我使用了 if([minimumValue intValue] == rect.size.height - point.y)) 但我认为这仍然比我自己的方法更好,我会在此基础上尝试一些方法并回复您。 @mMo 今天我又看了一遍代码并修复了一些问题。当我测试它时,它工作得很好。【参考方案2】:

这个答案对我不起作用,也许我混淆了rectpoint

我有另一个解决方案,它不需要循环,只需要检查一些方程式。

    首先,将屏幕分为四个区域。由于缺乏声誉,我现在无法发布图片,脚本在这里:http://i.stack.imgur.com/40Mos.jpg

    然后,写下空间坐标系中线条的公式

    最后,列出每个区域的方程式,现在您可以将方程式中的x y替换为终点的x y。

    CGPoint endPoint = [recognizer locationInView:self.view];
    CGFloat k = self.view.bounds.size.height / self.view.bounds.size.width;
    CGFloat b = self.view.bounds.size.height;
    
    if (endPoint.y < k * endPoint.x && endPoint.y < -1 * k * endPoint.x + b) 
        NSLog(@"top edge");
     else if (endPoint.y <= k * endPoint.x && endPoint.y >= -1 * k * endPoint.x + b) 
        NSLog(@"right edge");
     else if (endPoint.y > k * endPoint.x && endPoint.y > -1 * k * endPoint.x + b) 
        NSLog(@"bottom edge");
     else if (endPoint.y > k * endPoint.x && endPoint.y < -1 * k * endPoint.x + b) 
        NSLog(@"left edge");
    
    

【讨论】:

【参考方案3】:

您应该尝试仅对一个方向(x 或 y)应用捕捉;也许这样的事情可以工作:

- (CGPoint)closestPointForPoint:(CGPoint)point toSnapToInRect:(CGRect)rect 

CGPoint closestPoint = point;

/// Left/Right

if (MIN(point.x - rect.origin.x, rect.size.width - point.x) < MIN(point.y - rect.origin.y, rect.size.height - point.y)) 

  if ((point.x - rect.origin.x) > (rect.size.width - point.x)) 

    /// Point is closer to right side of frame, update the closestPoint's x.

    closestPoint.x = rect.size.width - (self.draggableView.frame.size.width / 2) - draggableViewMargin;
  
  else 
    /// Point is closer to left side of frame, update the closestPoint's x.
    closestPoint.x = rect.origin.x + (self.draggableView.frame.size.width / 2) + draggableViewMargin;
  

 else 
/// Top/Bottom

  if ((point.y - rect.origin.y) > (rect.size.height - point.y)) 
    /// Point is closer to top of frame, update the closestPoint's y.

    closestPoint.y = rect.size.height - (self.draggableView.frame.size.height / 2) - draggableViewMargin;
  
  else 

    /// Point is closer to bottom of frame, update the closestPoint's y.
    closestPoint.y = rect.origin.y + (self.draggableView.frame.size.height / 2) + draggableViewMargin;

  


return closestPoint;

【讨论】:

以上是关于在 iOS 中制作一个可拖动的 UIView 捕捉到边缘的主要内容,如果未能解决你的问题,请参考以下文章

UIView iOS 上的可拖动行为的名称是啥?

如何在画布上制作 HTML5 可拖动对象?

拖动 touchesBegan 后创建的 UIView

如何在 Java 中将多个可拖动图像添加到 JFrame?

让 jQuery 可拖动以捕捉到特定网格

用手指使 UIView 可拖动