博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【Android 进阶】仿抖音系列之翻页上下滑切换视频(一)
阅读量:6295 次
发布时间:2019-06-22

本文共 9759 字,大约阅读时间需要 32 分钟。

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

先说下思路,这里用重写了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
urlList; public void setUrlList(List
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) {            }        });

最后是源码

转载地址:http://olvta.baihongyu.com/

你可能感兴趣的文章
php--------获取当前时间、时间戳
查看>>
Spring MVC中文文档翻译发布
查看>>
docker centos环境部署tomcat
查看>>
JavaScript 基础(九): 条件 语句
查看>>
Linux系统固定IP配置
查看>>
配置Quartz
查看>>
Linux 线程实现机制分析
查看>>
继承自ActionBarActivity的activity的activity theme问题
查看>>
设计模式01:简单工厂模式
查看>>
项目经理笔记一
查看>>
Hibernate一对一外键双向关联
查看>>
mac pro 入手,php环境配置总结
查看>>
MyBatis-Plus | 最简单的查询操作教程(Lambda)
查看>>
rpmfusion 的国内大学 NEU 源配置
查看>>
spring jpa 配置详解
查看>>
IOE,为什么去IOE?
查看>>
Storm中的Worker
查看>>
dangdang.ddframe.job中页面修改表达式后进行检查
查看>>
Web基础架构:负载均衡和LVS
查看>>
Linux下c/c++相对路径动态库的生成与使用
查看>>