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)循环减少到在一些有序的表示(例如TreeSet
或TreeMap
)中的最近边缘的O(log n)搜索,这些均衡二叉搜索树是平衡二叉搜索树 。 这当然要求您为leftEdge
, rightEdge
, topEdge
和bottomEdge
每一个存储四个单独的已分类表示。
一个简单的例子是(只显示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
然后组合四个边的功能,以便更好地适应您的代码设计。