非全屏Activity中TextView触摸位置检测异常问题求助
问题描述
我正在开发一款简单的小游戏,目前遇到用户触摸视图检测异常的问题。测试发现Activity在全屏模式下运行完全正常,但我不想让它以全屏状态运行,请问该如何解决?
我实现全屏的代码如下:
requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
相关代码如下:
Activity代码
public class GameDrawActivity extends AppCompatActivity { public static Path path = new Path(); public static Paint paint_brush = new Paint(); static Rect outRect = new Rect(); static int[] location = new int[2]; static TextView[] views; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_game_draw); ConstraintLayout cl_container = findViewById(R.id.cl_container); int childNumber = cl_container.getChildCount(); views = new TextView[childNumber]; for(int i=0;i<childNumber;i++){ views[i] = (TextView) cl_container.getChildAt(i); } } public static void findView(int x, int y){ for(View view : views){ if(isViewInBounds(view, x, y)){ view.setBackgroundColor(Color.GREEN); return; } } } private static boolean isViewInBounds(View view, int x, int y){ view.getDrawingRect(outRect); view.getLocationOnScreen(location); outRect.offset(location[0], location[1]); return outRect.contains(x, y); } }
Display自定义View代码
public class Display extends View { public static ArrayList<Path> pathList = new ArrayList<>(); ... public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); switch (event.getAction()){ case MotionEvent.ACTION_DOWN: path.moveTo(x,y); invalidate(); return true; case MotionEvent.ACTION_MOVE: path.lineTo(x,y); pathList.add(path); invalidate(); GameDrawActivity.findView((int)x,(int)y); return true; default: return false; } } @Override protected void onDraw(Canvas canvas) { for(int i=0;i<pathList.size();i++){ paint_brush.setColor(Color.BLACK); canvas.drawPath(pathList.get(i), paint_brush); } } }
解决方案
问题核心是触摸坐标的坐标系不匹配:
- 全屏时,
event.getX()/event.getY()获取的View相对坐标,和getLocationOnScreen()的屏幕绝对坐标刚好匹配(无系统UI偏移); - 非全屏时,状态栏、标题栏会挤压View的显示区域,导致两种坐标系出现偏移,检测逻辑失效。
修复方案1:统一使用View相对坐标判断
修改isViewInBounds方法,将触摸点转换为目标View的相对坐标后再检测:
private static boolean isViewInBounds(View view, int x, int y){ int[] viewLocation = new int[2]; view.getLocationInWindow(viewLocation); // 把屏幕触摸坐标转为当前View的相对坐标 int touchXInView = x - viewLocation[0]; int touchYInView = y - viewLocation[1]; Rect outRect = new Rect(); view.getDrawingRect(outRect); return outRect.contains(touchXInView, touchYInView); }
修复方案2:统一使用屏幕绝对坐标
在onTouchEvent中获取屏幕绝对坐标,同时转换为View相对坐标用于绘图:
public boolean onTouchEvent(MotionEvent event) { // 获取触摸点的屏幕绝对坐标 float rawX = event.getRawX(); float rawY = event.getRawY(); // 转换为当前View的相对坐标,用于路径绘制 float viewX = rawX - getLeft(); float viewY = rawY - getTop(); switch (event.getAction()){ case MotionEvent.ACTION_DOWN: path.moveTo(viewX, viewY); invalidate(); return true; case MotionEvent.ACTION_MOVE: path.lineTo(viewX, viewY); pathList.add(path); invalidate(); // 传入屏幕绝对坐标给检测方法 GameDrawActivity.findView((int)rawX,(int)rawY); return true; default: return false; } }
此方案下原isViewInBounds方法无需修改。
额外优化
当前代码中pathList.add(path)会重复添加同一个Path对象,导致绘制时出现重复路径,建议每次触摸开始时创建新路径:
case MotionEvent.ACTION_DOWN: path = new Path(); path.moveTo(viewX, viewY); pathList.add(path); invalidate(); return true;
内容的提问来源于stack exchange,提问作者Treektus
相关产品推荐
相关产品推荐

