【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

### 配置Nginx以部署静态网站 为了使用Nginx部署静态网站,需要创建并配置相应的站点配置文件。此过程涉及指定服务器监听端口、定义根目录以及处理请求的方式。 #### 创建站点配置文件 假设要托管名为`www.example.com`的静态网站,在Nginx中可以通过编辑位于`sites-available/`下的配置文件来实现这一目标,并通过链接至`sites-enabled/`使该配置生效[^1]: ```nginx server { listen 80; server_name www.example.com; root /var/www/html/static-site; index index.html; location / { try_files $uri $uri/ =404; } } ``` 上述配置说明如下: - `listen 80;`: 表明Web服务器将在HTTP协议默认使用的第80号TCP端口上等待连接。 - `server_name www.example.com;`: 定义了响应哪个域名的请求。 - `root /var/www/html/static-site;`: 设置网页文档所在的绝对路径;这里假定HTML页面存放在`/var/www/html/static-site`下。 - `index index.html;`: 当访问者浏览到根URL时,默认加载`index.html`作为首页。 - `location / {...}`: 对于任何进入根路径的请求,尝试查找对应的物理文件或子目录中的索引页;如果找不到,则返回404错误。 完成以上设置之后,记得重启Nginx服务以便应用更改[^2]。 #### 测试Nginx安装版本 在确保一切正常工作之前,建议先验证当前系统的Nginx版本,这有助于排查可能存在的兼容性问题: ```bash nginx -v ``` 一旦确认无误,即可上传所需的静态资源(如HTML、CSS、JavaScript 文件等),并将它们放置在先前设定好的根目录内。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值