【问题标题】:Making a draggable UIView that snaps to edges in iOS在 iOS 中制作一个可拖动的 UIView 捕捉到边缘
【发布时间】: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 像素而不是角落。

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

谢谢

【问题讨论】:

  • 任何答案对你有用吗?

标签: ios uiview draggable


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

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

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

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

  3. 最后,列出每个区域的方程式,现在您可以将方程式中的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;
    }
    

    【讨论】:

      猜你喜欢
      • 2014-02-09
      • 2021-06-06
      • 2012-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多