Android onTouchListener多触点时ACTION_MOVE仅首触点触发如何解决
问题成因
MotionEvent.ACTION_MOVE事件不绑定单个触点索引:getActionIndex()方法仅对ACTION_POINTER_DOWN、ACTION_POINTER_UP这类单触点触发的事件有效,在ACTION_MOVE场景下返回的值无实际意义,默认返回0,因此原代码仅会更新索引为0的触点位置,其余触点完全未被处理。- 单次
ACTION_MOVE事件会携带当前所有活跃触点的位置信息,需要手动遍历所有触点索引才能完成全量位置更新,原代码只处理了单个索引的触点,因此后续触点不会触发位置更新逻辑。
修复方案
直接修改ACTION_MOVE分支的逻辑,遍历所有活跃触点逐个更新位置即可,修改后的触摸事件监听代码如下:
@SuppressLint("ClickableViewAccessibility") public GluSurfaceView(Context context, AppCompatActivity main) { super(context); setEGLContextClientVersion(3); renderer = new com.glu.engine.Renderer(main); setRenderer(renderer); setOnTouchListener((view, motionEvent) -> { int actionIndex = MotionEventCompat.getActionIndex(motionEvent); int actionMasked = motionEvent.getActionMasked(); if(actionMasked == MotionEvent.ACTION_MOVE){ // 遍历所有活跃触点,逐个更新位置 for (int i = 0; i < motionEvent.getPointerCount(); i++) { renderer.recordAction(i, motionEvent.getX(i),motionEvent.getY(i)); Log.w("OnTouchListener","we recorded a change! "+i+" has moved."); } return true; } if(actionMasked == MotionEvent.ACTION_UP){ renderer.stopAction(0); Log.w("onTouchListener","first Action stopped"); return true; } if(actionMasked == MotionEvent.ACTION_DOWN){ renderer.startAction(0); renderer.recordAction(0,motionEvent.getX(0),motionEvent.getY(0)); Log.w("onTouchListener","first Action!"); return true; } if(actionMasked == MotionEvent.ACTION_POINTER_DOWN){ renderer.addPointer(actionIndex); renderer.recordAction(actionIndex,motionEvent.getX(actionIndex),motionEvent.getY(actionIndex)); Log.w("onTouchListener","new Action! "+actionIndex); return true; } if(actionMasked == MotionEvent.ACTION_POINTER_UP) { renderer.removePointer(actionIndex); Log.w("onTouchListener","action "+actionIndex+" has stopped."); return true; } return false; }); }
额外优化建议
当前代码直接使用触点索引(index)作为标识存在潜在问题:当有中间触点抬起时,后续触点的索引会自动前移,可能导致存储的触点位置错乱。建议改用motionEvent.getPointerId(index)获取触点的唯一ID作为标识,索引仅用于读取当前事件的位置信息,用唯一ID匹配对应触点存储的数据,避免索引变动带来的异常。
内容的提问来源于stack exchange,提问作者user14587078
相关产品推荐
相关产品推荐

