Android中getLocationOnScreen返回错误负值问题排查
自定义View拖拽后获取屏幕坐标异常的解决办法
问题原因
你遇到的坐标负值问题,大概率是这两个原因:
ACTION_UP触发时,View的布局状态还未更新(拖拽操作刚结束,UI还没完成重绘),此时调用getLocationOnScreen拿到的是旧的布局坐标。- Fragment的根View可能嵌套在
ScrollView、ViewPager这类带滚动偏移的容器中,父容器的滚动量会抵消View的实际屏幕坐标,导致出现负值。
正确获取屏幕坐标的方案
方案1:延迟到UI刷新周期获取
利用View.post()把坐标获取逻辑放到下一次UI渲染周期,确保View布局状态稳定:
@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP: this.post(() -> { int[] screenLoc = new int[2]; getLocationOnScreen(screenLoc); // 此处screenLoc[0]、screenLoc[1]为正确的屏幕坐标 }); break; // 其他触摸事件处理逻辑 } return true; }
方案2:修正父容器的滚动偏移
如果父容器存在滚动行为,需要把父容器的滚动值叠加到坐标上:
@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP: int[] screenLoc = new int[2]; getLocationOnScreen(screenLoc); // 假设父容器是ScrollView,处理纵向偏移 ViewParent parent = getParent(); if (parent instanceof ScrollView) { ScrollView scrollView = (ScrollView) parent; screenLoc[1] += scrollView.getScrollY(); // 若为横向滚动容器,叠加scrollX:screenLoc[0] += scrollView.getScrollX() } // 修正后的screenLoc即为实际屏幕坐标 break; } return true; }
方案3:使用getGlobalVisibleRect替代
getGlobalVisibleRect直接返回View在屏幕上的可见区域,不受布局未更新的影响:
@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP: Rect visibleRect = new Rect(); getGlobalVisibleRect(visibleRect); // visibleRect.left = 屏幕X坐标,visibleRect.top = 屏幕Y坐标 break; } return true; }
内容的提问来源于stack exchange,提问作者AndrWeisR
相关产品推荐
相关产品推荐

