【Android】视频列表加载,小窗播放

文章详细介绍了如何在Android项目中使用GSYVideoPlayer库实现在列表中加载视频,当滑动列表时,如果播放的视频item离开屏幕,则切换到小窗播放模式。主要步骤包括引入依赖、创建布局、设置回调以及处理滚动事件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目需求

加载列表视频,点击视频可播放,当列表滑动的时候,播放视频的item不在界面上的时候,显示小窗播放。
如图所示:

视频列表

在这里插入图片描述

视频播放

在这里插入图片描述

视频滑动,窗口播放

在这里插入图片描述

需求实现

使用开源库【GSYVideoPlayer】播放器框架
开源项目链接: GSYVideoPlayer

1.引入依赖

    //视频播放器GSYVideoPlayer框架
    implementation 'com.github.CarGuo.GSYVideoPlayer:gsyVideoPlayer-java:v8.3.4-release-jitpack'
    //是否需要ExoPlayer模式
    implementation 'com.github.CarGuo.GSYVideoPlayer:GSYVideoPlayer-exo2:v8.3.4-release-jitpack'
    //是否需要AliPlayer模式
    implementation 'com.github.CarGuo.GSYVideoPlayer:GSYVideoPlayer-aliplay:8.3.4-release-jitpack'
    //更多ijk的编码支持
    implementation 'com.github.CarGuo.GSYVideoPlayer:gsyVideoPlayer-ex_so:v8.3.4-release-jitpack'

2.创建一个TestActivity页面布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".test.TestActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_test"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginStart="20dp"
        android:layout_marginTop="10dp"
        android:layout_marginEnd="20dp"
        android:layout_marginBottom="10dp"
        android:overScrollMode="never"
        android:scrollbars="none" />


    <FrameLayout
        android:id="@+id/ftest_video_full"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

3.创建TestActivity

class TestActivity : AppCompatActivity() {
    inner class TestBean(
        var httpStr: String
    )

    companion object {
        const val TAG = "TestActivity"
    }

    private lateinit var testAdapter: TestAdapter
    private var homeList: MutableList<TestBean> = ArrayList()

    private lateinit var layoutManager: LinearLayoutManager
    private lateinit var smallVideoHelper: GSYVideoHelper
    private lateinit var gsySmallVideoHelperBuilder: GSYVideoHelper.GSYVideoHelperBuilder
    private var lastVisibleItem = 0
    private var firstVisibleItem = 0
    private lateinit var binding: ActivityTestBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityTestBinding.inflate(layoutInflater)
        setContentView(binding.root)
        for (index in 0 until 20) {
            homeList.add(
                TestBean(
                    "https://vd3.bdstatic.com/mda-ic7ix5vebpup50sj/sc/mda-ic7ix5vebpup50sj.mp4?v_from_s=hkapp-haokan-hna&auth_key=1676626834-0-0-75b44d972c3736dc9b8bd5e11ce8c124&bcevod_channel=searchbox_feed&pd=1&cd=0&pt=3&logid=0634011548&vid=2616835831019383631&abtest=&klogid=0634011548"
                )
            )
        }

        layoutManager = LinearLayoutManager(this)
        testAdapter = TestAdapter(this, homeList)
        binding.rvTest.layoutManager = layoutManager
        binding.rvTest.adapter = testAdapter

        smallVideoHelper = GSYVideoHelper(this, NormalGSYVideoPlayer(this))
        smallVideoHelper.setFullViewContainer(binding.ftestVideoFull)

        //配置
        gsySmallVideoHelperBuilder = GSYVideoHelper.GSYVideoHelperBuilder()
        gsySmallVideoHelperBuilder
            .setHideActionBar(true)
            .setHideStatusBar(true)
            .setNeedLockFull(true)
            .setCacheWithPlay(true)
            .setAutoFullWithSize(true)
            .setShowFullAnimation(true)
            .setLockLand(true).setVideoAllCallBack(object : GSYSampleCallBack() {
                override fun onQuitSmallWidget(url: String, vararg objects: Any) {
                    super.onQuitSmallWidget(url, *objects)
                    //大于0说明有播放,//对应的播放列表TAG
                    if (smallVideoHelper.playPosition >= 0 && smallVideoHelper.playTAG == RecyclerItemViewHolder.TAG) {
                        //当前播放的位置
                        val position = smallVideoHelper.playPosition
                        //不可视的是时候
                        if (position < firstVisibleItem || position > lastVisibleItem) {
                            //释放掉视频
                            smallVideoHelper.releaseVideoPlayer()
                            testAdapter.notifyDataSetChanged()
                        }
                    }
                }
            })

        smallVideoHelper.setGsyVideoOptionBuilder(gsySmallVideoHelperBuilder)
        testAdapter.setVideoHelper(smallVideoHelper, gsySmallVideoHelperBuilder)

        binding.rvTest.addOnScrollListener(object : RecyclerView.OnScrollListener() {

            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                firstVisibleItem = layoutManager.findFirstVisibleItemPosition()
                lastVisibleItem = layoutManager.findLastVisibleItemPosition()
                //大于0说明有播放,//对应的播放列表TAG
                if (smallVideoHelper.playPosition >= 0 && smallVideoHelper.playTAG == RecyclerItemViewHolder.TAG) {
                    //当前播放的位置
                    val position = smallVideoHelper.playPosition
                    //不可视的时候
                    if (position < firstVisibleItem || position > lastVisibleItem) {
                        //如果是小窗口就不需要处理
                        if (!smallVideoHelper.isSmall && !smallVideoHelper.isFull) {
                            //小窗口
                            val size = CommonUtil.dip2px(this@TestActivity, 150f)
                            //actionbar为true才不会掉下面去
                            smallVideoHelper.showSmallVideo(Point(size, size), true, true)
                        }
                    } else {
                        if (smallVideoHelper.isSmall) {
                            smallVideoHelper.smallVideoToNormal()
                        }
                    }
                }
            }
        })
    }


    override fun onDestroy() {
        super.onDestroy()
        smallVideoHelper.releaseVideoPlayer()
        GSYVideoManager.releaseAllVideos()
    }

4.清单文件配置,这个需要配置,不然当视频播放的时候全屏显示会出现问题崩溃

        <activity
            android:name=".TestActivity"
            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
            android:exported="true"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:windowSoftInputMode="adjustPan">
            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>

5.item 的布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <FrameLayout
        android:id="@+id/test_item_container"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:layout_marginTop="8dp"
        android:background="#FFFFFF"
        android:scaleType="centerCrop" />
        
    <ImageView
        android:id="@+id/test_item_btn"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_centerInParent="true"
        android:src="@drawable/video_click_play_selector" />
</RelativeLayout>

6.TestAdapter

public class TestAdapter extends RecyclerView.Adapter {

    private final static String TAG = "RecyclerHomeAdapter";
    private final Context context;
    private GSYVideoHelper smallVideoHelper;
    private GSYVideoHelper.GSYVideoHelperBuilder gsyVideoHelperBuilder;
    private final List<TestActivity.TestBean> itemDataList;

    public TestAdapter(Context context, List<TestActivity.TestBean> itemDataList) {
        this.itemDataList = itemDataList;
        this.context = context;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.item_test, parent, false);
        return new TestItemViewHolder(context, view);

    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
            TestItemViewHolder recyclerItemViewHolder = (TestItemViewHolder) holder;
            recyclerItemViewHolder.setVideoHelper(smallVideoHelper, gsyVideoHelperBuilder);
            recyclerItemViewHolder.setRecyclerBaseAdapter(this);
            recyclerItemViewHolder.onBind(position, itemDataList);
    }

    @Override
    public int getItemCount() {
        return itemDataList.size();
    }

    public GSYVideoHelper getVideoHelper() {
        return smallVideoHelper;
    }

    public void setVideoHelper(GSYVideoHelper smallVideoHelper, GSYVideoHelper.GSYVideoHelperBuilder gsyVideoHelperBuilder) {
        this.smallVideoHelper = smallVideoHelper;
        this.gsyVideoHelperBuilder = gsyVideoHelperBuilder;
    }
}

7.TestItemViewHolder

public class TestItemViewHolder extends RecyclerItemBaseHolder {
    public final static String TAG = "RecyclerItemViewHolder";
    private FrameLayout frameLayout;
    private ImageView imaPlay;
    private ImageView imaBackground;

    private GSYVideoHelper smallVideoHelper;
    private GSYVideoHelper.GSYVideoHelperBuilder gsyVideoHelperBuilder;

    public TestItemViewHolder(Context context, @NonNull View itemView) {
        super(itemView);
        frameLayout = itemView.findViewById(R.id.test_item_container);
        imaPlay = itemView.findViewById(R.id.test_item_btn);
        imaBackground = new ImageView(context);

    }

    public void onBind(final int position, List<TestActivity.TestBean> list) {
        imaBackground.setScaleType(ImageView.ScaleType.CENTER_CROP);
        imaBackground.setImageResource(R.mipmap.ic_dog);

        smallVideoHelper.addVideoPlayer(position, imaBackground, TAG, frameLayout, imaPlay);
        imaPlay.setOnClickListener(new View.OnClickListener() {
            @SuppressLint("NotifyDataSetChanged")
            @Override
            public void onClick(View v) {
                smallVideoHelper.setPlayPositionAndTag(position, TAG);
                getRecyclerBaseAdapter().notifyDataSetChanged();

                gsyVideoHelperBuilder.setSurfaceErrorPlay(true)
                        .setUrl(list.get(position).getHttpStr());
                smallVideoHelper.startPlay();
            }
        });
    }

    public void setVideoHelper(GSYVideoHelper smallVideoHelper, GSYVideoHelper.GSYVideoHelperBuilder gsySmallVideoHelperBuilder) {
        this.smallVideoHelper = smallVideoHelper;
        this.gsyVideoHelperBuilder = gsySmallVideoHelperBuilder;
    }
}

8.RecyclerItemBaseHolder

public class RecyclerItemBaseHolder extends RecyclerView.ViewHolder {

    RecyclerView.Adapter adapter;

    public RecyclerItemBaseHolder(@NonNull View itemView) {
        super(itemView);
    }

    public RecyclerView.Adapter getRecyclerBaseAdapter() {
        return adapter;
    }

    public void setRecyclerBaseAdapter(RecyclerView.Adapter recyclerBaseAdapter) {
        this.adapter = recyclerBaseAdapter;
    }
}

OVER

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值