GUI构建器中找到的对齐准则/捕捉算法

我尝试实现一个类似于许多GUI构建器的行为:当前拖动的组件应该与另一个组件对齐,如果它们几乎处于水平或垂直线上。 我目前的做法是遍历所有放置的组件,并检查是否有任何四边(几乎)与拖动组件边缘对齐:

for (v in rootView.relativeLayout.children()) { // x val left = event.rawX - dXInit val right = event.rawX - dXInit + view.width val leftEdgeRange = (v.leftEdge() - 50 .. v.leftEdge() + 50) val rightEdgeRange = (v.rightEdge() - 50 .. v.rightEdge() + 50) when (left) { in leftEdgeRange -> x = v.leftEdge() in rightEdgeRange -> x = v.rightEdge() } when (right) { in leftEdgeRange -> x = v.leftEdge() - view.width in rightEdgeRange -> x = v.rightEdge() - view.width } // y val top = event.rawY - dYInit val bottom = event.rawY - dYInit + view.height val topEdgeRange = (v.topEdge() - 50 .. v.topEdge() + 50) val bottomEdgeRange = (v.bottomEdge() - 50 .. v.bottomEdge() + 50) when (top) { in topEdgeRange -> y = v.topEdge() in bottomEdgeRange -> y = v.bottomEdge() } when (bottom) { in topEdgeRange -> y = v.topEdge() - view.height in bottomEdgeRange -> y = v.bottomEdge() - view.height } } 

 fun View.topEdge() = y fun View.bottomEdge() = y + height fun View.leftEdge() = x fun View.rightEdge() = x + width 

但是这看起来效率不高,因为这是在onTouch调用的 ,所以这个循环运行得非常频繁。 有更好的方法吗? 一般的或Java的答案是受欢迎的。

一个更有效的方法是将遍历所有视图的O(n)循环减少到在一些有序的表示(例如TreeSetTreeMap 中的最近边缘的O(log n)搜索,这些均衡二叉搜索树是平衡二叉搜索树 。 这当然要求您为leftEdgerightEdgetopEdgebottomEdge每一个存储四个单独的已分类表示。

一个简单的例子是(只显示leftEdge ,其他的是相似的):

 val viewsByLeftEdge = TreeMap<Int, View>() 

要将视图添加到地图中,请使用:

 viewsByLeftEdge[view.leftEdge()] = view 

(请注意,如果多个视图具有相同的左边缘值,则只有最后一个视图将存储在此地图中)

然后,不是遍历所有视图,而是找到给定left坐标的最近左边缘:

 val floorL = viewsByLeftEdge.floorKey(left) val ceilingL = viewsByLeftEdge.ceilingKey(left) val nearestL = when { floorL == null -> ceilingL ceilingL == null -> floorL ceilingL - left < left - floorL -> ceilingL else -> floorL } if (nearestL in left - 50 .. left + 50) x = nearestL 

这里, .floorKey(x)返回映射中小于或等于x的最高边缘坐标,如果没有这样的坐标,则返回null 。 同样, .ceilingKey(x)返回地图中最大的x ,或者返回null

这需要O(log n)时间,并且将比遍历任何大量视图的所有视图更快。 如果您不需要通过边缘获取视图,可以通过用TreeSet<Int>替换TreeMap<Int, View>来简化代码(函数为floor(x)ceiling(x)

您可以将这些地图放在代码中,填入您的View然后组合四个边的功能,以便更好地适应您的代码设计。