美文网首页Android-RecyclerViewAndroid项目UI
【Android 进阶】仿抖音系列之翻页上下滑切换视频(一)

【Android 进阶】仿抖音系列之翻页上下滑切换视频(一)

作者: 欢子3824 | 来源:发表于2018-10-12 16:01 被阅读599次

    最近公司在做个短视频的项目,其中借鉴了很多抖音的设计,其中就有抖音的上下滑切换视频。

    先说下思路,这里用重写了ViewPager的onInterceptTouchEvent和onTouchEvent方法,使其可以上下滑动切换视图。

    代码如下

    /**
     * 作者: ch
     * 时间: 2018/7/30 0030-下午 2:53
     * 描述:
     * 来源:
     */
    
    
    public class VerticalViewPager extends ViewPager {
    
        private boolean isVertical = false;
    
        public VerticalViewPager(@NonNull Context context) {
            super(context);
        }
    
        public VerticalViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
        }
    
        private void init() {
            // The majority of the magic happens here
            setPageTransformer(true, new HorizontalVerticalPageTransformer());
            // The easiest way to get rid of the over scroll drawing that happens on the left and right
            setOverScrollMode(OVER_SCROLL_NEVER);
        }
    
    
        public boolean isVertical() {
            return isVertical;
        }
    
        public void setVertical(boolean vertical) {
            isVertical = vertical;
            init();
        }
    
        private class HorizontalVerticalPageTransformer implements PageTransformer {
    
            private static final float MIN_SCALE = 0.75f;
    
            @Override
            public void transformPage(View page, float position) {
                if (isVertical) {
    
                    if (position < -1) {
                        page.setAlpha(0);
                    } else if (position <= 1) {
                        page.setAlpha(1);
    
                        // Counteract the default slide transition
                        float xPosition = page.getWidth() * -position;
                        page.setTranslationX(xPosition);
    
                        //set Y position to swipe in from top
                        float yPosition = position * page.getHeight();
                        page.setTranslationY(yPosition);
                    } else {
                        page.setAlpha(0);
                    }
                } else {
                    int pageWidth = page.getWidth();
    
                    if (position < -1) { // [-Infinity,-1)
                        // This page is way off-screen to the left.
                        page.setAlpha(0);
    
                    } else if (position <= 0) { // [-1,0]
                        // Use the default slide transition when moving to the left page
                        page.setAlpha(1);
                        page.setTranslationX(0);
                        page.setScaleX(1);
                        page.setScaleY(1);
    
                    } else if (position <= 1) { // (0,1]
                        // Fade the page out.
                        page.setAlpha(1 - position);
    
                        // Counteract the default slide transition
                        page.setTranslationX(pageWidth * -position);
                        page.setTranslationY(0);
    
                        // Scale the page down (between MIN_SCALE and 1)
                        float scaleFactor = MIN_SCALE
                                + (1 - MIN_SCALE) * (1 - Math.abs(position));
                        page.setScaleX(scaleFactor);
                        page.setScaleY(scaleFactor);
    
                    } else { // (1,+Infinity]
                        // This page is way off-screen to the right.
                        page.setAlpha(0);
                    }
                }
            }
        }
    
        /**
         * Swaps the X and Y coordinates of your touch event.
         */
        private MotionEvent swapXY(MotionEvent ev) {
            float width = getWidth();
            float height = getHeight();
    
            float newX = (ev.getY() / height) * width;
            float newY = (ev.getX() / width) * height;
    
            ev.setLocation(newX, newY);
    
            return ev;
        }
    
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            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 (isVertical) {
                return super.onTouchEvent(swapXY(ev));
            } else {
                return super.onTouchEvent(ev);
            }
        }
    
    }
    
    

    在上下滑的时候,不可见时,要暂停视频,可见时重新播放,这里使用的是fragment,通过其生命周期来控制视频的播放与暂停。

    通过setUserVisibleHint、onResume、onPause、onDestroy 4个方法处理视频的播放、暂停、重新播放、销毁逻辑

           private void initView() {
            VerticalViewPagerAdapter pagerAdapter = new VerticalViewPagerAdapter(getSupportFragmentManager());
            vvpBackPlay.setVertical(true);
            //设置viewpager 缓存数,可以根据需要调整
            vvpBackPlay.setOffscreenPageLimit(10);
            pagerAdapter.setUrlList(urlList);
            vvpBackPlay.setAdapter(pagerAdapter);
        }
    
    public class VerticalViewPagerAdapter extends PagerAdapter {
        private FragmentManager fragmentManager;
        private FragmentTransaction mCurTransaction;
        private Fragment mCurrentPrimaryItem = null;
        private List<String> urlList;
    
        public void setUrlList(List<String> urlList) {
            this.urlList = urlList;
        }
    
    
        public VerticalViewPagerAdapter(FragmentManager fm) {
            this.fragmentManager = fm;
        }
    
        @Override
        public int getCount() {
            return Integer.MAX_VALUE;
        }
    
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
    
            if (mCurTransaction == null) {
                mCurTransaction = fragmentManager.beginTransaction();
            }
    
            VideoFragment fragment = new VideoFragment();
            if (urlList != null && urlList.size() > 0) {
                Bundle bundle = new Bundle();
                if (position >= urlList.size()) {
                    bundle.putString(VideoFragment.URL, urlList.get(position % urlList.size()));
                } else {
                    bundle.putString(VideoFragment.URL, urlList.get(position));
                }
                fragment.setArguments(bundle);
            }
    
    
            mCurTransaction.add(container.getId(), fragment,
                    makeFragmentName(container.getId(), position));
            fragment.setUserVisibleHint(false);
    
            return fragment;
        }
    
    
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            if (mCurTransaction == null) {
                mCurTransaction = fragmentManager.beginTransaction();
            }
            mCurTransaction.detach((Fragment) object);
            mCurTransaction.remove((Fragment) object);
        }
    
        @Override
        public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
            return ((Fragment) object).getView() == view;
        }
    
        private String makeFragmentName(int viewId, int position) {
            return "android:switcher:" + viewId + position;
        }
    
        @Override
        public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
            Fragment fragment = (Fragment) object;
            if (fragment != mCurrentPrimaryItem) {
                if (mCurrentPrimaryItem != null) {
                    mCurrentPrimaryItem.setMenuVisibility(false);
                    mCurrentPrimaryItem.setUserVisibleHint(false);
                }
                if (fragment != null) {
                    fragment.setMenuVisibility(true);
                    fragment.setUserVisibleHint(true);
                }
                mCurrentPrimaryItem = fragment;
            }
        }
    
        @Override
        public void finishUpdate(ViewGroup container) {
            if (mCurTransaction != null) {
                mCurTransaction.commitNowAllowingStateLoss();
                mCurTransaction = null;
            }
        }
    }
    
    

    由于公司项目中用到了腾讯云直播相关的东西,所以播放器这里用的是腾讯的TXCloudVideoView播放器,可以替换成其他播放器。

    public class VideoFragment extends BaseFragment {
        @BindView(R.id.txv_video)
        TXCloudVideoView txvVideo;
        @BindView(R.id.rl_back_right)
        RelativeLayout rlBackRight;
        @BindView(R.id.dl_back_play)
        DrawerLayout dlBackPlay;
        @BindView(R.id.iv_play_thun)
        ImageView ivPlayThun;
        private TXVodPlayer mVodPlayer;
        private String url;
        public static final String URL = "URL";
    
        @Override
        protected int getLayoutId() {
            return R.layout.fm_video;
        }
    
        @Override
        protected void initView() {
    
            url = getArguments().getString(URL);
            //创建player对象
            mVodPlayer = new TXVodPlayer(context);
    //关键player对象与界面view
            mVodPlayer.setPlayerView(txvVideo);
    //        url = "http://v.cctv.com/flash/mp4video6/TMS/2011/01/05/cf752b1c12ce452b3040cab2f90bc265_h264818000nero_aac32-1.mp4";
            mVodPlayer.setLoop(true);
    
            Glide.with(context)
                    .load(url)
                    .into(ivPlayThun);
        }
    
        @Override
        protected void loadData() {
            mVodPlayer.startPlay(url);
        }
    
        @Override
        public void setUserVisibleHint(boolean isVisibleToUser) {
            super.setUserVisibleHint(isVisibleToUser);
    
            if (mVodPlayer == null) {
                return;
            }
            if (isVisibleToUser) {
                mVodPlayer.resume();
            } else {
                mVodPlayer.pause();
            }
    
        }
    
        @Override
        public void onResume() {
    
            super.onResume();
            if (mVodPlayer != null) {
                mVodPlayer.resume();
            }
    
        }
    
        @Override
        public void onPause() {
            super.onPause();
            if (mVodPlayer != null) {
                mVodPlayer.pause();
            }
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            if (mVodPlayer != null) {
                // true代表清除最后一帧画面
                mVodPlayer.stopPlay(true);
            }
            if (txvVideo != null) {
                txvVideo.onDestroy();
            }
        }
    
    
    }
    
    

    要实现抖音那种可以无限上滑的,可以在ViewPager 的onPageSelected 中判断position

      mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                }
    
                @Override
                public void onPageSelected(int position) {
                    if (position == list.size() - 2) {
                        //倒数第2个 加载数据
                        page++;
                        addData();
    
                    }
                }
    
                @Override
                public void onPageScrollStateChanged(int state) {
                }
            });
    

    最后是源码Github

    你的认可,是我坚持更新博客的动力,如果觉得有用,就请点个赞,谢谢

    相关文章

      网友评论

      • wethereornot:你的视频集合是如何传的,我传的实体类,然后播放不了,这个视频集合都在那里用了?
        我.在adapter中改了视频播放地址,你这里面还有一个super,里面我也没见有什么特殊操作啊
      • wethereornot:大佬有左滑查看详情功能么?(类似抖音的左滑)
        欢子3824:有的,可以使用DrawerLayout,github上的代码里有,注释掉了,也可以用viewpager,j加载2个fragment,将垂直滑动VerticalViewPager 当做一个fragment,用户主页当做另外一个fragment

      本文标题:【Android 进阶】仿抖音系列之翻页上下滑切换视频(一)

      本文链接:https://www.haomeiwen.com/subject/uglgaftx.html