You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

非全屏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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 13:05:29