在 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】:这个答案对我不起作用,也许我混淆了rect
和point
我有另一个解决方案,它不需要循环,只需要检查一些方程式。
首先,将屏幕分为四个区域。由于缺乏声誉,我现在无法发布图片,脚本在这里: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 捕捉到边缘的主要内容,如果未能解决你的问题,请参考以下文章