if (getCurrentItem() == 0 && getChildCount() == 0) {
 return false;
 }
 if (isVertical) {
 boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
 swapXY(ev);
 // return touch coordinates to original reference frame for any child views
 return intercepted;
 } else {
 return super.onInterceptTouchEvent(ev);
 }
 }@Override
 public boolean onTouchEvent(MotionEvent ev) {
 if (getCurrentItem() == 0 && getChildCount() == 0) {
 return false;
 }
 if (isVertical) {
 return super.onTouchEvent(swapXY(ev));
 } else {
 return super.onTouchEvent(ev);
 }
 }
 }3.2 ViewPager和Fragment
• 采用了ViewPager+FragmentStatePagerAdapter+Fragment来处理。为何选择使用FragmentStatePagerAdapter,主要是因为使用 FragmentStatePagerAdapter更省内存,但是销毁后新建也是需要时间的。一般情况下,如果你是用于ViewPager展示数量特别多的条目时,那么建议使用FragmentStatePagerAdapter。关于PagerAdapter的深度解析,可以我这篇文章:PagerAdapter深度解析和实践优化
• 在activity中的代码如下所示
private void initViewPager() {
 List list = new ArrayList<>();
 ArrayList fragments = new ArrayList<>();
 for (int a = 0; a< DataProvider.VideoPlayerList.length ; a++){
 Video video = new Video(DataProvider.VideoPlayerTitle[a],
 10,“”,DataProvider.VideoPlayerList[a]);
 list.add(video);
 fragments.add(VideoFragment.newInstant(DataProvider.VideoPlayerList[a]));
 }
 vp.setOffscreenPageLimit(1);
 vp.setCurrentItem(0);
 vp.setOrientation(DirectionalViewPager.VERTICAL);
 FragmentManager supportFragmentManager = getSupportFragmentManager();
 MyPagerAdapter myPagerAdapter = new MyPagerAdapter(fragments, supportFragmentManager);
 vp.setAdapter(myPagerAdapter);
 }class MyPagerAdapter extends FragmentStatePagerAdapter{
private ArrayList list;
public MyPagerAdapter(ArrayList list , FragmentManager fm){
 super(fm);
 this.list = list;
 }@Override
 public Fragment getItem(int i) {
 return list.get(i);
 }@Override
 public int getCount() {
 return list!=null ? list.size() : 0;
 }
 }• 那么在fragment中如何处理呢?关于视频播放器,这里可以看我封装的库,视频lib

public class VideoFragment extends Fragment{
public VideoPlayer videoPlayer;
 private String url;
 private int index;@Override
 public void onStop() {
 super.onStop();
 VideoPlayerManager.instance().releaseVideoPlayer();
 }public static Fragment newInstant(String url){
 VideoFragment videoFragment = new VideoFragment();
 Bundle bundle = new Bundle();
 bundle.putString(“url”,url);
 videoFragment.setArguments(bundle);
 return videoFragment;
 }@Override
 public void onCreate(@Nullable Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 Bundle arguments = getArguments();
 if (arguments != null) {
 url = arguments.getString(“url”);
 }
 }@Nullable
 @Override
 public View onCreateView(@NonNull LayoutInflater inflater,
 @Nullable ViewGroup container,
 @Nullable Bundle savedInstanceState) {
 View view = inflater.inflate(R.layout.fragment_video, container, false);
 return view;
 }@Override
 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
 super.onViewCreated(view, savedInstanceState);
 videoPlayer = view.findViewById(R.id.video_player);
 }@Override
 public void onActivityCreated(@Nullable Bundle savedInstanceState) {
 super.onActivityCreated(savedInstanceState);
 Log.d(“初始化操作”,“------”+index++);
 VideoPlayerController controller = new VideoPlayerController(getActivity());
 videoPlayer.setUp(url,null);
 videoPlayer.setPlayerType(ConstantKeys.IjkPlayerType.TYPE_IJK);
 videoPlayer.setController(controller);
 ImageUtils.loadImgByPicasso(getActivity(),“”,
 R.drawable.image_default,controller.imageView());
 }
 }3.3 修改滑动距离翻页
• 需求要求必须手动触摸滑动超过1/2的时候松开可以滑动下一页,没有超过1/2返回原页,首先肯定是重写viewpager,只能从源码下手。经过分析,源码滑动的逻辑处理在此处,truncator的属性代表判断的比例值!
• 这个方法会在切页的时候重定向Page,比如从第一个页面滑动,结果没有滑动到第二个页面,而是又返回到第一个页面,那个这个page会有重定向的功能
private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) {
 int targetPage;
 if (Math.abs(deltaX) > this.mFlingDistance && Math.abs(velocity) > this.mMinimumVelocity) {
 targetPage = velocity > 0 ? currentPage : currentPage + 1;
 } else {
 float truncator = currentPage >= this.mCurItem ? 0.4F : 0.6F;
 targetPage = currentPage + (int)(pageOffset + truncator);
 }if (this.mItems.size() > 0) {
 ViewPager.ItemInfo firstItem = (ViewPager.ItemInfo)this.mItems.get(0);
 ViewPager.ItemInfo lastItem = (ViewPager.ItemInfo)this.mItems.get(this.mItems.size() - 1);
 targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position));
 }return targetPage;
 }• determineTargetPage这个方法就是计算接下来要滑到哪一页。这个方法调用是在MotionEvent.ACTION_UP这个事件下,先说下参数意思:
• currentPage:当前ViewPager显示的页面
• pageOffset:用户滑动的页面偏移量
• velocity: 滑动速率
• deltaX: X方向移动的距离
• 进行debug调试之后,发现问题就在0.4f和0.6f这个参数上。分析得出:0.6f表示用户滑动能够翻页的偏移量,所以不难理解,为啥要滑动半屏或者以上了。
• 也可以修改Touch事件
• 控制ViewPager的Touch事件,这个基本是万能的,毕竟是从根源上入手的。你可以在onTouchEvent和onInterceptTouchEvent中做逻辑的判断。但是比较麻烦。
3.4 修改滑动速度
• 使用viewPager进行滑动时,如果通过手指滑动来进行的话,可以根据手指滑动的距离来实现,但是如果通过setCurrentItem函数来实现的话,则会发现直接闪过去的,会出现一下刷屏。想要通过使用setCurrentItem函数来进行viewpager的滑动,并且需要有过度滑动的动画,那么,该如何做呢?
• 具体可以分析setCurrentItem源码的逻辑,然后会看到scrollToItem方法,这个特别重要,主要是处理滚动过程中的逻辑。最主要关心的也是smoothScrollTo函数,这个函数中,可以看到具体执行滑动的其实就一句话,就是mScroller.startScroll(sx,sy,dx,dy,duration),则可以看到,是mScroller这个对象进行滑动的。那么想要改变它的属性,则可以通过反射来实现。
• 代码如下所示,如果是手指触摸滑动,则可以加快一点滑动速率,当然滑动持续时间你可以自己设置。通过自己自定义滑动的时间,就可以控制滑动的速度。
@TargetApi(Build.VERSION_CODES.KITKAT)
 public void setAnimationDuration(final int during){
 try {
 // viewPager平移动画事件
 Field mField = ViewPager.class.getDeclaredField(“mScroller”);
 mField.setAccessible(true);
 // 动画效果与ViewPager的一致
 Interpolator interpolator = new Interpolator() {
 @Override
 public float getInterpolation(float t) {
 t -= 1.0f;
 return t * t * t * t * t + 1.0f;
 }
 };
 Scroller mScroller = new Scroller(getContext(),interpolator){
 final int time = 2000;
 @Override
 public void startScroll(int x, int y, int dx, int dy, int duration) {
 // 如果手工滚动,则加速滚动
 if (System.currentTimeMillis() - mRecentTouchTime > time) {
 duration = during;
 } else {
 duration /= 2;
 }
 super.startScroll(x, y, dx, dy, duration);
 }@Override
 public void startScroll(int x, int y, int dx, int dy) {
 super.startScroll(x, y, dx, dy,during);
 }
 };
 mField.set(this, mScroller);
 } catch (NoSuchFieldException | IllegalAccessException | IllegalArgumentException e) {
 e.printStackTrace();
 }
 }04.用RecyclerView实现
4.1 自定义LayoutManager
• 自定义LayoutManager,并且继承LinearLayoutManager,这样就得到一个可以水平排向或者竖向排向的布局策略。如果你接触过SnapHelper应该了解一下LinearSnapHelper和PagerSnapHelper这两个子类类,LinearSnapHelper可以实现让列表的Item居中显示的效果,PagerSnapHelper就可以做到一次滚动一个item显示的效果。
• 重写onChildViewAttachedToWindow方法,在RecyclerView中,当Item添加进来了调用这个方法。这个方法相当于是把view添加到window时候调用的,也就是说它比draw方法先执行,可以做一些初始化相关的操作。
/**
• 该方法必须调用
• @param recyclerView recyclerView
 */
 @Override
 public void onAttachedToWindow(RecyclerView recyclerView) {
 if (recyclerView == null) {
 throw new IllegalArgumentException(“The attach RecycleView must not null!!”);
 }
 super.onAttachedToWindow(recyclerView);
 this.mRecyclerView = recyclerView;
 if (mPagerSnapHelper==null){
 init();
 }
 mPagerSnapHelper.attachToRecyclerView(mRecyclerView);
 mRecyclerView.addOnChildAttachStateChangeListener(mChildAttachStateChangeListener);
 }4.2 添加滑动监听
• 涉及到一次滑动一页视频,那么肯定会有视频初始化和释放的功能。那么思考一下哪里来开始播放视频和在哪里释放视频?不要着急,要监听滑动到哪页,需要我们重写onScrollStateChanged()函数,这里面有三种状态:SCROLL_STATE_IDLE(空闲),SCROLL_STATE_DRAGGING(拖动),SCROLL_STATE_SETTLING(要移动到最后位置时)。
• 我们需要的就是RecyclerView停止时的状态,我们就可以拿到这个View的Position,注意这里还有一个问题,当你通过这个position去拿Item会报错,这里涉及到RecyclerView的缓存机制,自己去脑补~~。打印Log,你会发现RecyclerView.getChildCount()一直为1或者会出现为2的情况。来实现一个接口然后通过接口把状态传递出去。
• 自定义监听listener事件
public interface OnPagerListener {
/**
• 初始化完成
 */
 void onInitComplete();/**
• 释放的监听
• @param isNext 是否下一个
• @param position 索引
 */
 void onPageRelease(boolean isNext,int position);/***
• 选中的监听以及判断是否滑动到底部
• @param position 索引
• @param isBottom 是否到了底部
 */
 void onPageSelected(int position,boolean isBottom);
 }• 获取到RecyclerView空闲时选中的Item,重写LinearLayoutManager的onScrollStateChanged方法
/**
• 滑动状态的改变
• 缓慢拖拽-> SCROLL_STATE_DRAGGING
• 快速滚动-> SCROLL_STATE_SETTLING
• 空闲状态-> SCROLL_STATE_IDLE
• @param state 状态
 */
 @Override
 public void onScrollStateChanged(int state) {
 switch (state) {
 case RecyclerView.SCROLL_STATE_IDLE:
 View viewIdle = mPagerSnapHelper.findSnapView(this);
 int positionIdle = 0;
 if (viewIdle != null) {
 positionIdle = getPosition(viewIdle);
 }
 if (mOnViewPagerListener != null && getChildCount() == 1) {
 mOnViewPagerListener.onPageSelected(positionIdle,
 positionIdle == getItemCount() - 1);
 }
 break;
 case RecyclerView.SCROLL_STATE_DRAGGING:
 View viewDrag = mPagerSnapHelper.findSnapView(this);
 if (viewDrag != null) {
 int positionDrag = getPosition(viewDrag);
 }
 break;
 case RecyclerView.SCROLL_STATE_SETTLING:
 View viewSettling = mPagerSnapHelper.findSnapView(this);
 if (viewSettling != null) {
 int positionSettling = getPosition(viewSettling);
 }
 break;
 default:
 break;
 }
 }4.3 监听页面是否滚动
• 这里有两个方法scrollHorizontallyBy()和scrollVerticallyBy()可以拿到滑动偏移量,可以判断滑动方向。
/**
• 监听竖直方向的相对偏移量
• @param dy y轴滚动值
• @param recycler recycler
• @param state state滚动状态
• @return int值
 */
 @Override
 public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
 if (getChildCount() == 0 || dy == 0) {
 return 0;
 }
 this.mDrift = dy;
 return super.scrollVerticallyBy(dy, recycler, state);
 }/**
• 监听水平方向的相对偏移量
• @param dx x轴滚动值
• @param recycler recycler
• @param state state滚动状态
• @return int值
 */
 @Override
 public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
 if (getChildCount() == 0 || dx == 0) {
 return 0;
 }
 this.mDrift = dx;
 return super.scrollHorizontallyBy(dx, recycler, state);
 }