• Stars
    star
    376
  • Rank 113,810 (Top 3 %)
  • Language
    Java
  • License
    Apache License 2.0
  • Created over 5 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

仿抖音,快手,短视频,竖直方向,一次滚动一个页面的封装库。目前支持ViewPager做法,也支持RecyclerView做法……使用ViewPager则只是修改滑动速率,以及滚动翻页过渡时间;使用recyclerView打造丝滑切换视频的功能,更多内容可以看demo

YCScrollPager目录介绍

目录介绍

  • 01.先来看一下需求
  • 02.有几种实现方式
    • 2.1 使用ViewPager
    • 2.2 使用RecyclerView
  • 03.具体使用
    • 3.0 如何引用该lib
    • 3.1 ViewPager实现方式
    • 3.2 RecyclerView实现方式
  • 04.部分优化点
    • 4.1 ViewPager改变滑动速率
    • 4.2 PagerSnapHelper注意点
    • 4.3 自定义LayoutManager注意点
  • 05.关于通用视频播放器
    • 5.1 通用视频播放器
    • 5.2 视频播放器架构图
  • 06.其他说明介绍

00.先来看一下效果图

image image image image image image image image image image image image

01.先来看一下需求

  • 项目中的视频播放,要求实现抖音那种竖直方向一次滑动一页的效果。
    • 滑动要流畅不卡顿,并且手动触摸滑动超过1/2的时候松开可以滑动下一页,没有超过1/2返回原页。
  • 手指拖动页面滑动,只要没有切换到其他的页面,视频都是在播放的。切换了页面,上一个视频销毁,该页面则开始初始化播放。
  • 切换页面的时候过渡效果要自然,避免出现闪屏。具体的滑动效果,可以直接参考抖音……

02.有几种实现方式

2.1 使用ViewPager

  • 使用ViewPager实现竖直方法上下切换视频分析
    • 1.最近项目需求中有用到需要在ViewPager中播放视频,就是竖直方法上下滑动切换视频,视频是网络视频,最开始的实现思路是ViewPager中根据当前item位置去初始化SurfaceView,同时销毁时根据item的位置移除SurfaceView。
    • 2.上面那种方式确实是可以实现的,但是存在2个问题,第一,MediaPlayer的生命周期不容易控制并且存在内存泄漏问题。第二,连续三个item都是视频时,来回滑动的过程中发现会出现上个视频的最后一帧画面的bug。
    • 3.未提升用户体验,视频播放器初始化完成前上面会覆盖有该视频的第一帧图片,但是发现存在第一帧图片与视频第一帧信息不符的情况,后面会通过代码给出解决方案。
  • 大概的实现思路是这样
    • 1.需要自定义一个竖直方向滑动的ViewPager,注意这个特别重要。
    • 2.一次滑动一页,建议采用ViewPager+FragmentStatePagerAdapter+Fragment方式来做,后面会详细说。
    • 3.视频的初始化逻辑和销毁逻辑优化,性能和滑动流畅度分析和探讨。
  • 不太建议使用ViewPager
    • 1.ViewPager 自带的滑动效果完全满足场景,而且支持Fragment和View等UI绑定,只要对布局和触摸事件部分作一些修改,就可以把横向的 ViewPager 改成竖向。
    • 2.但是没有复用是个最致命的问题。在onLayout方法中,所有子View会实例化并一字排开在布局上。当Item数量很大时,将会是很大的性能浪费。
    • 3.其次是可见性判断的问题。很多人会以为 Fragment 在 onResume 的时候就是可见的,而 ViewPager 中的 Fragment 就是个反例,尤其是多个 ViewPager 嵌套时,会同时有多个父 Fragment 多个子 Fragment 处于 onResume 的状态,却只有其中一个是可见的。除非放弃 ViewPager 的预加载机制。在页面内容曝光等重要的数据上报时,就需要判断很多条件:onResumed 、 setUserVisibleHint 、 setOnPageChangeListener 等。

2.2 使用RecyclerView

  • 使用RecyclerView实现树枝方向上下切换视频分析
    • 1.首先RecyclerView它设置竖直方向滑动是十分简单的,同时关于item的四级缓存也做好了处理,而且滑动的效果相比ViewPager要好一些。
    • 2.滑动事件处理比viewPager好,即使你外层潜逃了下拉刷新上拉加载的布局,也不影响后期事件冲突处理,详细可以看demo案例。
  • 大概的实现思路是这样
    • 1.自定义一个LinearLayoutManager,重写onScrollStateChanged方法,注意是拿到滑动状态。
    • 2.一次滑动切换一个页面,可以使用PagerSnapHelper来实现,十分方便简单。
    • 3.在recyclerView对应的adapter中,在onCreateViewHolder初始化视频操作,同时当onViewRecycled时,销毁视频资源。

03.具体使用

3.0 如何引用该lib

  • 直接添加依赖即可
    implementation 'com.github.yangchong211:YCScrollPager:1.0.5'
    

3.1 ViewPager实现方式

3.1.1 使用VerticalViewPager的方式如下所示
  • 在布局中
    <com.yc.pagerlib.pager.VerticalViewPager
        android:id="@+id/vp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    
  • 在activity中,这里是Viewpager+FragmentStatePagerAdapter+Fragment
    private void initViewPager() {
        List<Video> list = new ArrayList<>();
        ArrayList<Fragment> 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<Fragment> list;
    
        public MyPagerAdapter(ArrayList<Fragment> 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中做视频播放相关操作
    @Override
    public void onStop() {
        super.onStop();
        VideoPlayerManager.instance().releaseVideoPlayer();
    }
    
    @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.2 RecyclerView实现方式

  • 代码中直接使用PagerLayoutManager,如下所示
    PagerLayoutManager viewPagerLayoutManager = new PagerLayoutManager(
            this, OrientationHelper.VERTICAL);
    recyclerView.setLayoutManager(viewPagerLayoutManager);
    
  • 设置layoutManager初始化和销毁相关的监听
    viewPagerLayoutManager.setOnViewPagerListener(new OnPagerListener() {
        @Override
        public void onInitComplete() {
            System.out.println("OnPagerListener---onInitComplete--"+"初始化完成");
        }
    
        @Override
        public void onPageRelease(boolean isNext, int position) {
            System.out.println("OnPagerListener---onPageRelease--"+position+"-----"+isNext);
        }
    
        @Override
        public void onPageSelected(int position, boolean isBottom) {
            System.out.println("OnPagerListener---onPageSelected--"+position+"-----"+isBottom);
        }
    });
    

04.部分优化点

4.1 ViewPager改变滑动速率

  • 可以通过反射修改属性,注意,使用反射的时候,建议手动try-catch,避免异常导致崩溃。代码如下所示:
    /**
     * 修改滑动灵敏度
     * @param flingDistance                     滑动惯性,默认是75
     * @param minimumVelocity                   最小滑动值,默认是1200
     */
    public void setScrollFling(int flingDistance , int minimumVelocity){
        try {
            Field mFlingDistance = ViewPager.class.getDeclaredField("mFlingDistance");
            mFlingDistance.setAccessible(true);
            Object o = mFlingDistance.get(this);
            Log.d("setScrollFling",o.toString());
            //默认值75
            mFlingDistance.set(this, flingDistance);
    
            Field mMinimumVelocity = ViewPager.class.getDeclaredField("mMinimumVelocity");
            mMinimumVelocity.setAccessible(true);
            Object o1 = mMinimumVelocity.get(this);
            Log.d("setScrollFling",o1.toString());
            //默认值1200
            mMinimumVelocity.set(this,minimumVelocity);
        } catch (Exception e){
            e.printStackTrace();
        }
    }
    

4.2 PagerSnapHelper注意点

  • 好多时候会抛出一个异常"illegalstateexception an instance of onflinglistener already set".
  • 看SnapHelper源码attachToRecyclerView(xxx)方法时,可以看到如果recyclerView不为null,则先destoryCallback(),它作用在于取消之前的RecyclerView的监听接口。然后通过setupCallbacks()设置监听器,如果当前RecyclerView已经设置了OnFlingListener,会抛出一个状态异常。那么这个如何复现了,很容易,你初始化多次就可以看到这个bug。
  • 建议手动捕获一下该异常,代码设置如下所示。源码中判断了,如果onFlingListener已经存在的话,再次设置就直接抛出异常,那么这里可以增强一下逻辑判断,ok,那么问题便解决呢!
    try {
        //attachToRecyclerView源码上的方法可能会抛出IllegalStateException异常,这里手动捕获一下
        RecyclerView.OnFlingListener onFlingListener = mRecyclerView.getOnFlingListener();
        //源码中判断了,如果onFlingListener已经存在的话,再次设置就直接抛出异常,那么这里可以判断一下
        if (onFlingListener==null){
            mPagerSnapHelper.attachToRecyclerView(mRecyclerView);
        }
    } catch (IllegalStateException e){
        e.printStackTrace();
    }
    

4.3 自定义LayoutManager注意点

  • 网上有人已经写了一篇自定义LayoutManager实现抖音的效果的博客,我自己也很仔细看了这篇文章。不过我觉得有几个注意要点,因为要用到线上app,则一定要尽可能减少崩溃率……
  • 通过SnapHelper调用findSnapView方法,得到的view,一定要增加非空判断逻辑,否则很容易造成崩溃。
  • 在监听滚动位移scrollVerticallyBy的时候,注意要增加判断,就是getChildCount()如果为0时,则需要返回0。
  • 在onDetachedFromWindow调用的时候,可以把listener监听事件给remove掉。

05.关于通用视频播放器

5.1 通用视频播放器

  • 基础封装视频播放器player,可以在ExoPlayer、MediaPlayer,声网RTC视频播放器内核,原生MediaPlayer可以自由切换
  • 对于视图状态切换和后期维护拓展,避免功能和业务出现耦合。比如需要支持播放器UI高度定制,而不是该lib库中UI代码
  • 针对视频播放,音频播放,播放回放,以及视频直播的功能。使用简单,代码拓展性强,封装性好,主要是和业务彻底解耦,暴露接口监听给开发者处理业务具体逻辑
  • 该播放器整体架构:播放器内核(自由切换) + 视频播放器 + 边播边缓存 + 高度定制播放器UI视图层
  • 项目地址:https://github.com/yangchong211/YCVideoPlayer
  • 关于视频播放器整体功能介绍文档:https://juejin.im/post/6883457444752654343

5.2 视频播放器架构图

image

06.其他说明介绍

关于其他内容介绍

image

其他推荐

  • 博客笔记大汇总【15年10月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计47篇[近20万字],转载请注明出处,谢谢!
  • 链接地址:https://github.com/yangchong211/YCBlogs
  • 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!

关于LICENSE

Copyright 2017 yangchong211(github.com/yangchong211)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

More Repositories

1

YCBlogs

技术博客笔记大汇总,包括Java基础,线程,并发,数据结构;Android技术博客等等;常用设计模式;常见的算法;网络协议知识点;部分flutter笔记;还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!转载请注明出处,谢谢!
6,403
star
2

YCAppTool

🔥🔥🔥 组件化综合案例,组件分层为:基础公共组件,功能组件,业务组件,主工程。每一层组件的建设,很详细的工程案例,很全面的一个组件化实践案例。一个超级综合案例!
Java
3,172
star
3

YCVideoPlayer

🔥🔥🔥 基础封装视频播放器player,可以在ExoPlayer、MediaPlayer原生MediaPlayer可以自由切换内核;该播放器整体架构:播放器内核(自由切换) + 视频播放器 + 边播边缓存 + 高度定制播放器UI视图层。支持视频简单播放,列表播放,仿抖音滑动播放,自动切换播放,使用案例丰富,拓展性强。
Java
2,192
star
4

YCWebView

基于腾讯x5开源库,提高webView开发效率,大概要节约你百分之六十的时间成本。该案例支持处理js的交互逻辑且无耦合、同时暴露进度条加载进度、可以监听异常error状态、支持视频播放并且可以全频、支持加载word,xls,ppt,pdf,txt等文件文档、发短信、打电话、发邮件、打开文件操作上传图片、唤起原生App、支持webView页面截图、x5库为最新版本,功能强大。
Java
1,735
star
5

YCAndroidTool

用于项目测试,崩溃重启操作,崩溃记录日志【可以查看,分享】和重启【多种重启app方式】;网路拦截查看的工具小助手,拦截请求和响应数据,统计接口请求次数,流量消耗,以及统计网络链接/dns解析/request请求/respond响应等时间。提高开发效率……
Java
749
star
6

YCStateLayout

State switching, so that the View state switch and Activity completely separate. Using builder mode to freely add the required state View, can set data, data is empty, load data error, network error, load and other states, and support the layout of custom state. At present has been used in other formal projects, strong expansion!
Java
556
star
7

YCSlideLayout

购物商场商品详情页面自定义控件,模仿淘宝、京东、考拉等商品详情页分页加载的UI效果。可以嵌套RecyclerView、WebView、ViewPager、ScrollView等等。支持设置上拉分页加载动画效果……
Java
491
star
8

YCCustomText

自定义文本控件,支持富文本,包含两种状态:编辑状态和预览状态。编辑状态中,可以对插入本地或者网络图片,可以同时插入多张有序图片和删除图片,支持图文混排,并且可以对文字内容简单操作加粗字体,设置字体下划线,支持设置文字超链接(超链接支持跳转),已经用于多个实际项目中……
Java
479
star
9

YCRefreshView

自定义支持上拉加载更多,下拉刷新,可以自定义头部和底部,可以添加多个headerView,使用一个原生recyclerView就可以搞定复杂界面。支持自由切换状态【加载中,加载成功,加载失败,没网络等状态】的控件,可以自定义状态视图View。拓展功能【支持长按拖拽,侧滑删除】,轻量级,可以选择性添加 。持续更新……
Java
454
star
10

YCUpdateApp

轻量级版本更新弹窗,弹窗上支持更新进度条,可以设置普通更新或者强制更新。解决8.0以上通知栏不显示问题,解决7.0以上安装apk异常,下载完成则会自动提示安装;下载异常,失败,错误等状态,支持重启下载任务;还支持自定义下载路径。代码量少,调用简单……
Java
446
star
11

YCCaptureTool

App综合防抓包实践,关闭代理,设置配置文件;设置单向认证或双向认证;对数据加密和解密;sign签名参数;防止xposed,root,va挂载等操作。 比较通用全面的防抓包技术方案!
Java
421
star
12

YCNotification

通知栏封装库,强大的通知栏工具类,链式编程调用,解决了8.0以上通知栏不显示问题,支持多种不同的使用场景,兼容老版本。还有自定义通知栏view,可高度定制布局……
Java
376
star
13

YCDialog

自定义弹窗,其中包括:自定义Toast;自定义dialog控件;自定义DialogFragment弹窗;自定义PopupWindow弹窗;还有自定义Snackbar等等;简单便用。目前已经用于多个正式项目中。
Java
359
star
14

YCStudyCpp

🔥🔥🔥 c++学习案例,系统学习,c++教程,基础案例,数据类型,变量和常量,运算符,表达式,判断和循环,函数,模版函数,指针,引用,数组和容器,IO输入和输出,结构和类,继承和派生,多线程,并发,线程安全锁,内存分配,堆和栈,异常,STL标准模版,预处理器,信号处理,程序调试,网络通信,综合案例等等
C++
353
star
15

YCStatusBar

关于状态栏方案总结案例,适合于绝大多数的使用场景……同时,兼容了小米,魅族等手机状态栏字体颜色设置失效问题。已经用于实际项目投资界,新芽,沙丘大学等APP,一键集成并使用!支持单Activity多Fragment动态修改状态栏颜色,入侵性低,一行代码即可实现你需要的需求
Java
313
star
16

YCJniHelper

JNI学习案例,通过简单的案例快速入门jni开发。JNI基础语法介绍,so库生成打包和反编译,Java和C/C++相关调用案例
Java
266
star
17

YCFlutterUtils

Flutter Utils 全网最齐全的工具类。包含bus,颜色,日期,文件,json,log,sp,加解密,num,图片,网络,正则,验证,路由,文本,时间,spi,计时器,拓展类,编解码,发射,异常,字节转化,解析等等工具类。
Dart
245
star
18

YCThreadPool

轻量级简易线程池库,轻量级线程池异步库,支持线程执行过程中状态回调监测(包含成功,失败,异常等多种状态);支持创建异步任务,可以设置线程的名称,延迟执行时间,线程优先级,回调callback等;可以根据自己需要创建自己需要的线程池;线程异常时,可以打印异常日志,避免崩溃。
Java
224
star
19

YCCommonLib

组件化开发中基础公共库,activity栈管理;fragment周期监听;Lru缓存库;反射库;分区存储;Log日志打印和存储;通用缓存库(支持sp,mmkv,lru,disk,fastsp等多种存储方式切换);App重启;通用全面的工具类Utils;通用基类fragment,adpater,activity等简单封装;intent内容打印到控制台库;通用基础接口
Java
191
star
20

YCWidgetLib

自定义控件,其中包含自定义折叠布局,拓展性强使用简单;万能自定义红点控件,充分解耦合接入方便;多种方案实现阴影效果库;自定义view和viewGroup圆角控件,彻底解决圆角问题等
Java
186
star
21

YCWalleHelper

瓦力多渠道打包的Python脚本测试工具,通过该自动化脚本,自需要run一下或者命令行运行脚本即可实现美团瓦力多渠道打包,打包速度很快。配置信息十分简单,代码中已经注释十分详细。可以自定义输出文件路径,可以修改多渠道配置信息,简单实用。
Tcl
133
star
22

YCBannerView

轮播图,支持多种自定义属性,可以设置轮播红点或者轮播数字,支持设置引导页。可以根据不同使用场景,可以选择无限循环,静态管理或者动态管理adapter,还可以设置暂停和开始轮播。后期添加了RecyclerView轮播图,同时自定义多种类型SnapHelper,卡片滑动流畅,目前已经用于多个正式项目中!!
Java
106
star
23

YCLeetcode

组件之间的通信,很友好起到隔离效果,接口+实现类,使用注解生成代码方式,无需手动注册,将使用步骤简单化,支持组件间以暴露接口提供服务的方式进行通信。
Java
76
star
24

YCStudyWeb

Web学习案例
JavaScript
71
star
25

YCToolLib

通用工具库组件,包括前后台判断,拦截器时间,心跳轮询库,Task任务库,二维码扫码库,转场动画库,通用TTS音频播放库,国际化locale库等等
Java
66
star
26

YCServerLib

gRPC学习案例,使用gRPC作为网络方案可以带来高效性、跨平台和语言、可靠性、易于使用和可扩展性等收益。同时可以减少手动编写代码的工作量,提高开发效率。
Java
51
star
27

YCStudyC

系统性学习C编程,变量,数据类型,循环,选择,输入和输出,数组和容器,函数,结构体,指针,预处理,文件操作,调试等。练习多个完整小项目:学生管理系统,贪吃蛇,万年历,推箱子,五子棋。是入手学习C的练习完整项目
C
49
star
28

YCDesignHelper

注解学习小案例,比较系统性学习注解并且应用实践。简单应用了运行期注解,通过注解实现了setContentView功能;简单应用了编译器注解,通过注解实现了防暴力点击的功能,同时支持设置时间间隔;使用注解替代枚举;使用注解一步步搭建简单路由案例。结合相应的博客,在来一些小案例,从此应该对注解有更加深入的理解……
Java
45
star
29

YCDesignBlog

设计模式,创建型设计模式,结构型设计模式,行为型设计模式,面向对象设计原则,六大设计原则,面向对象设计思想,项目架构演进。持续迭代笔记和完善案例,打造全网系统高质量的设计模式笔记!
Java
44
star
30

YCTimerHelper

倒计时工具,分别使用了handler,自定义CountDownTimer,Timer和TimerTask,chronometer控件,和属性动画实现倒计时的功能。封装CountDownTimer倒计时器【在原有基础上增加了暂停和恢复倒计时功能】,解决了倒计时无法到0和从最大值开始bug
Java
13
star
31

YCJavaBlog

Java高级进阶专栏博客,数据类型原理,泛型设计思想,面向对象,继承,封装,io流,序列化,拷贝,高效读写,反射,注解,spi机制,异常,四种引用,线程原理,线程通信,线程池设计思想,线程并发优化,上下文切换原理,CAS,锁的设计和原理,类加载,对象布局,代码攻击,内存模型,即时编译,内存回收机制,性能调优,集合设计思想
Java
7
star
32

YCComputerBlog

计算机基础博客,计算机组成原理,存储器的设计,局部性原理,地址映射,CPU处理器用途,指令架构,CPU性能,缓存一致性,Cache,MESI协议,伪共享,CPU三级缓存设计思想,输入和输出,总线系统设计,指令编程,程序如何运行,内存存储设计,物理内存和虚拟内存,共享内存设计,计算机二进制的由来,异常处理,IO流操作
4
star
33

YCSplashSdk

打开app启动页sdk,支持图片广告,也支持视频
3
star
34

YCUniApp

uni开发的项目,由于公司项目做混合开发,因此边学边做。基础入门级的案例分析,近期学习更新中
Vue
3
star
35

YCPluginTool

Plugin插件学习工具
2
star
36

YCAndroidBlog

Android技术专栏
1
star
37

yangchong211

1
star