Android中如何获取自定义HtMarkerView在ConstraintLayout父布局中的位置?
嘿,我之前也碰到过一模一样的坑!你在自定义HtMarkerView的onTouchEvent里调用getTop()总是拿到0,大概率是这几个原因导致的,咱们一步步排查解决:
1. 先检查布局约束是否完整
看你贴的布局代码,HtMarkerView只设置了水平方向的start约束,但完全没有垂直方向的约束(比如top_toTopOf、bottom_toBottomOf这类)。在ConstraintLayout里,如果子View缺少某一方向的约束,布局系统会默认把它钉在该方向的起始位置——垂直方向就是顶部,所以getTop()自然返回0。
如果你的MarkerView本来就应该放在某个垂直位置,先补全约束试试,比如让它垂直居中:
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"
补完约束后再调用getTop(),数值就正常了。
2. 确保在布局完成后获取位置
如果约束没问题,但还是拿到0,那可能是你调用getTop()的时机太早了。ConstraintLayout的子View位置是在布局测量(onMeasure)和摆放(onLayout)完成后才确定的,如果在onCreate/onStart这些生命周期方法里直接调用,此时View还没被摆到正确位置,返回0很正常。
要是你在Activity/Fragment里获取位置,用post()延迟执行就好:
chaLevelMarker.post(new Runnable() { @Override public void run() { int relativeTop = chaLevelMarker.getTop(); int relativeLeft = chaLevelMarker.getLeft(); // 这里拿到的就是相对于父ConstraintLayout的正确位置 } });
如果是在自定义HtMarkerView的onTouchEvent里获取,触摸事件触发时布局肯定已经完成了,这时候还返回0的话,就要检查自定义View的onMeasure方法是不是没写对——如果你的View没有正确处理测量逻辑,布局系统可能没法正确计算它的位置。比如确保onMeasure里正确设置测量尺寸:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 按布局xml中指定的宽高完成测量 int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(width, height); }
3. 用绝对位置计算相对位置(备选方案)
要是上面的方法都没解决,还可以通过获取View和父布局的绝对位置,手动计算相对距离:
// 获取MarkerView在窗口中的绝对坐标 int[] viewPos = new int[2]; chaLevelMarker.getLocationInWindow(viewPos); // 获取父ConstraintLayout在窗口中的绝对坐标 int[] parentPos = new int[2]; constraintLayoutScopeView.getLocationInWindow(parentPos); // 计算相对于父布局的位置 int relativeTop = viewPos[1] - parentPos[1]; int relativeLeft = viewPos[0] - parentPos[0];
这种方法不受布局时机和约束的影响,总能拿到正确的相对位置。
内容的提问来源于stack exchange,提问作者haiwuxing

