我尝试实现与许多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答案。
答案 0 :(得分:1)
更有效的方法是减少 O(n)循环,迭代所有视图到 O(log n)搜索最近的边缘一些排序的表示,如TreeSet
或TreeMap
,balanced binary search trees。当然,这需要您为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)时间,并且比任何大量视图的所有视图都要快。如果您不需要按其边缘获取视图,请将TreeMap<Int, View>
替换为TreeSet<Int>
来简化代码(函数则为floor(x)
和ceiling(x)
。
您可以将地图放在代码中,然后使用View
填充它们,并为适合您代码设计的四条边组成函数。