RecyclerView中VideoView点击监听异常求助:响应慢/滚动误触
解决RecyclerView中VideoView点击监听异常的问题
我太懂这种踩坑的感觉了!RecyclerView里的VideoView触摸事件总是有各种幺蛾子,咱们一步步来解决:
问题根源分析
- 多次点击才触发:你设置的
MediaController默认会拦截触摸事件,哪怕你把它设为GONE,它的触摸拦截逻辑还是在跑,导致你的点击事件被它吃掉了好几次才轮到VideoView。 - 滚动时触发OnTouch:直接用
OnTouchListener的ACTION_DOWN判断,会把RecyclerView滚动前的按下动作当成点击,根本区分不开“点击”和“滚动”操作。
解决方案
1. 用GestureDetector区分点击与滚动
代替直接的OnTouchListener,用GestureDetector来识别真正的点击动作(手指抬起且没有产生滚动),这样就不会在滚动时误触发了。
首先在你的ViewHolder里初始化GestureDetector:
private GestureDetector gestureDetector; // 在ViewHolder的构造方法中初始化 public YourViewHolder(View itemView, final OnMediaPressedListener listener) { super(itemView); // ... 其他控件初始化 gestureDetector = new GestureDetector(itemView.getContext(), new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent e) { // 这里才是真正的点击事件触发点 int position = getAdapterPosition(); if (position != RecyclerView.NO_POSITION) { listener.onMediaPressed(position); } return true; } @Override public boolean onDown(MotionEvent e) { // 必须返回true,否则后续的触摸事件不会被GestureDetector处理 return true; } }); }
然后修改setVideo方法里的触摸监听,把事件交给GestureDetector处理:
videoContent.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return gestureDetector.onTouchEvent(event); } });
2. 自定义MediaController取消触摸拦截
默认的MediaController会拦截触摸事件,哪怕它不可见,咱们自定义一个不拦截事件的MediaController:
public class NoInterceptMediaController extends MediaController { public NoInterceptMediaController(Context context) { super(context); } @Override public boolean onTouchEvent(MotionEvent event) { // 不处理触摸事件,让事件传递给VideoView return false; } @Override public boolean onInterceptTouchEvent(MotionEvent event) { // 不拦截触摸事件 return false; } }
然后替换原来的MediaController初始化:
// 把原来的MediaController换成自定义的 MediaController mc = new NoInterceptMediaController(mContext); mc.setVisibility(View.GONE); mc.setAnchorView(videoContent); mc.setMediaPlayer(videoContent); videoContent.setMediaController(mc);
3. 优化视频准备逻辑(可选)
你原来的OnPreparedListener里有些逻辑可以简化,避免不必要的MediaPlayer重建:
MediaPlayer.OnPreparedListener PreparedListener = new MediaPlayer.OnPreparedListener(){ @Override public void onPrepared(MediaPlayer m) { try { m.setVolume(0f, 0f); m.setLooping(true); // 这里不用stop再start,直接start就行 m.start(); } catch (Exception e) { e.printStackTrace(); } } };
为什么这样有效?
GestureDetector的onSingleTapUp只会在用户完成一次点击(按下-抬起,没有滚动)时触发,完美区分点击和滚动操作。- 自定义的
NoInterceptMediaController不再拦截触摸事件,让VideoView能正常接收到点击信号,不会出现多次点击才触发的情况。
内容的提问来源于stack exchange,提问作者Alexandru Nitu
相关产品推荐
相关产品推荐

