ViewPager或RecyclerView嵌套MediaController的滚动问题

在Android的UI设计中,很容易遇到在ViewPager的某个Fragment中使用了ViewView,或者在RecyclerView嵌套了一个视频列表(使用VideoView),而VideoView中会使用MediaController的进度条控件,如果不做任何调整,会发现视频进度条没有办法拖动(Scroll),每次Scroll都是滑动ViewPager,或者误滑动了RecyclerView。这里就分享一下如何解决这个问题。

以下没有贴所有的代码,可能有信息缺失引起歧义,可以发送邮件到hugh@inner-peace.cn 咨询和探讨。

问题的主要原因是因为Scroll事件的传递问题,由于Scroll事件被更外层的控件给截获阻断,导致内层的MediaController无法获取到Scroll事件,导致出现问题。所以只要外层不处理或者透传,既可以解决问题。

而上面提到的Scroll事件,并不是直接有个什么onScroll这种方式,而是由两个比较重要的Touch事件影响:onTouchEvent和onInterceptTouchEvent。

public class MyViewPager extends ViewPager {

    public MyViewPager(@NonNull Context context) {
        super(context);
    }   

    public MyViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }   

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // 这里的Adapter是我自定义的Adapter,继承于FragmentPagerAdapter,不是重点,所以不展开
        ViewPagerAdapter adapter = (ViewPagerAdapter) getAdapter();
        if (adapter == null) {
            return super.onInterceptTouchEvent(ev);
        }   

        // isVideoControllerShown是自定义的函数,用来获取MediaController是否处于展示可滑动的状态
        return (!adapter.isVideoControllerShown()) && super.onInterceptTouchEvent(ev);
    }   

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        ViewPagerAdapter adapter = (ViewPagerAdapter) getAdapter();
        if (adapter == null) {
            return super.onTouchEvent(ev);
        }   

        return (!adapter.isVideoControllerShown()) && super.onTouchEvent(ev);
    }   
}

以上这段代码的意思是,在自定义的MyViewPager控件中的一个Fragment里面有一个视频播放器,在MediaController(进度条)展示的时候,ViewPager不允许滑动,这样就不会出现用户在滑动进度条时,出现Fragment切换。这两个事件什么意思,简单归纳一下:

  • onTouchEvent:响应触摸事件,包含ACTION_DOWN,ACTION_MOVE,ACTION_UP,ACTION_CANCEL一些事件,如果不处理就返回False。如果返回True则不会向下传递;
  • onInterceptTouchEvent:是否阻拦Touch事件,如果返回False则不阻拦。

所以根据adapter中获取MediaController的状态,如果处于展示状态,那么ViewPager不能滑动Fragment,并且将Touch事件传递到MediaController。