饺子播放器RecyclerView自动播放

mac2025-08-27  10

饺子播放器RecyclerView自动播放

项目地址:https://github.com/AndroidLMY/JzPlayer

效果图如下

添加相关依赖

implementation 'com.google.android.material:material:1.0.0' implementation 'androidx.recyclerview:recyclerview:1.0.0' implementation 'cn.jzvd:jiaozivideoplayer:7.0.5' implementation 'com.github.bumptech.glide:glide:4.8.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'

如果添加以上依赖报下面的错误

请在build中android节点下添加

compileOptions { targetCompatibility 1.8 sourceCompatibility 1.8 }

清单文件添加网络权限

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" />

自定义播放器MyJzvdStd继承JzvdStd类

package com.androidlmy.jzplayer; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.SeekBar; import cn.jzvd.JzvdStd; /** * 这里可以监听到视频播放的生命周期和播放状态 * 所有关于视频的逻辑都应该写在这里 * Created by Nathen on 2017/7/2. */ public class MyJzvdStd extends JzvdStd { public MyJzvdStd(Context context) { super(context); } public MyJzvdStd(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void init(Context context) { super.init(context); } @Override public void onClick(View v) { super.onClick(v); int i = v.getId(); if (i == cn.jzvd.R.id.fullscreen) { Log.i(TAG, "onClick: fullscreen button"); } else if (i == R.id.start) { Log.i(TAG, "onClick: start button"); } } @Override public boolean onTouch(View v, MotionEvent event) { super.onTouch(v, event); int id = v.getId(); if (id == cn.jzvd.R.id.surface_container) { switch (event.getAction()) { case MotionEvent.ACTION_UP: if (mChangePosition) { Log.i(TAG, "Touch screen seek position"); } if (mChangeVolume) { Log.i(TAG, "Touch screen change volume"); } break; } } return false; } @Override public int getLayoutId() { return R.layout.jz_layout_std; } @Override public void startVideo() { super.startVideo(); Log.i(TAG, "startVideo"); } @Override public void onStopTrackingTouch(SeekBar seekBar) { super.onStopTrackingTouch(seekBar); Log.i(TAG, "Seek position "); } @Override public void gotoScreenFullscreen() { super.gotoScreenFullscreen(); Log.i(TAG, "goto Fullscreen"); } @Override public void gotoScreenNormal() { super.gotoScreenNormal(); Log.i(TAG, "quit Fullscreen"); } @Override public void autoFullscreen(float x) { super.autoFullscreen(x); Log.i(TAG, "auto Fullscreen"); } @Override public void onClickUiToggle() { super.onClickUiToggle(); Log.i(TAG, "click blank"); } //onState 代表了播放器引擎的回调,播放视频各个过程的状态的回调 @Override public void onStateNormal() { super.onStateNormal(); } @Override public void onStatePreparing() { super.onStatePreparing(); } @Override public void onStatePlaying() { super.onStatePlaying(); } @Override public void onStatePause() { super.onStatePause(); } @Override public void onStateError() { super.onStateError(); } @Override public void onStateAutoComplete() { super.onStateAutoComplete(); Log.i(TAG, "Auto complete"); } //changeUiTo 真能能修改ui的方法 @Override public void changeUiToNormal() { super.changeUiToNormal(); } @Override public void changeUiToPreparing() { super.changeUiToPreparing(); } @Override public void changeUiToPlayingShow() { super.changeUiToPlayingShow(); } @Override public void changeUiToPlayingClear() { super.changeUiToPlayingClear(); } @Override public void changeUiToPauseShow() { super.changeUiToPauseShow(); } @Override public void changeUiToPauseClear() { super.changeUiToPauseClear(); } @Override public void changeUiToComplete() { super.changeUiToComplete(); } @Override public void changeUiToError() { super.changeUiToError(); } @Override public void onInfo(int what, int extra) { super.onInfo(what, extra); } @Override public void onError(int what, int extra) { super.onError(what, extra); } }

编写PlayerAdapter

package com.androidlmy.jzplayer; import android.annotation.SuppressLint; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import cn.jzvd.JzvdStd; /** * @功能: * @Creat 2019/11/1 15:11 * @User Lmy * @Compony zaituvideo */ public class PlayerAdapter extends RecyclerView.Adapter<PlayerAdapter.ViewHolder> { private Context context; public PlayerAdapter(Context context) { this.context = context; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { ViewHolder holder = new ViewHolder(LayoutInflater.from( context).inflate(R.layout.item_recyclerview, parent, false)); return holder; } @SuppressLint("LongLogTag") @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.videoplayer.setUp("http://jzvd.nathen.cn/6ea7357bc3fa4658b29b7933ba575008/fbbba953374248eb913cb1408dc61d85-5287d2089db37e62345123a1be272f8b.mp4", "", JzvdStd.SCREEN_NORMAL); holder.videoplayer.setVideoImageDisplayType(1); holder.videoplayer.thumbImageView.setScaleType(ImageView.ScaleType.FIT_XY); // holder.videoplayer.startVideo();//自动播放 在recyclerview有bug Glide.with(holder.videoplayer.getContext()).load("http://jzvd-pic.nathen.cn/jzvd-pic/00b026e7-b830-4994-bc87-38f4033806a6.jpg"). into(holder.videoplayer.thumbImageView); } @Override public int getItemCount() { return 10; } class ViewHolder extends RecyclerView.ViewHolder { private MyJzvdStd videoplayer; public ViewHolder(View itemView) { super(itemView); videoplayer = itemView.findViewById(R.id.videoplayer); } } }

主页面布局和Recyclerview的Item布局如下

<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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=".MainActivity"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> <?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="300dp"> <com.androidlmy.jzplayer.MyJzvdStd android:id="@+id/videoplayer" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>

主界面MainActivity代码如下:

package com.androidlmy.jzplayer; import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import android.content.Context; import android.graphics.Rect; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Bundle; import android.view.KeyEvent; import android.view.View; import cn.jzvd.Jzvd; import static cn.jzvd.Jzvd.STATE_PAUSE; import static cn.jzvd.Jzvd.STATE_PLAYING; public class MainActivity extends AppCompatActivity { private RecyclerView recyclerView; private PlayerAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView = findViewById(R.id.recycler_view); adapter = new PlayerAdapter(this); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(adapter); recyclerView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() { @Override public void onChildViewAttachedToWindow(View view) { } @Override public void onChildViewDetachedFromWindow(View view) { Jzvd jzvd = view.findViewById(R.id.videoplayer); if (jzvd != null && Jzvd.CURRENT_JZVD != null && jzvd.jzDataSource.containsTheUrl(Jzvd.CURRENT_JZVD.jzDataSource.getCurrentUrl())) { if (Jzvd.CURRENT_JZVD != null && Jzvd.CURRENT_JZVD.screen != Jzvd.SCREEN_FULLSCREEN) { Jzvd.releaseAllVideos(); } } } }); recyclerView.addOnScrollListener(new AutoPlayScrollListener(this)); } /** * 监听recycleView滑动状态, * 自动播放可见区域内的第一个视频 */ private static class AutoPlayScrollListener extends RecyclerView.OnScrollListener { private int firstVisibleItem = 0; private int lastVisibleItem = 0; private int visibleCount = 0; private Context context; public AutoPlayScrollListener(Context context) { this.context = context; } /** * 被处理的视频状态标签 */ private enum VideoTagEnum { /** * 自动播放视频 */ TAG_AUTO_PLAY_VIDEO, /** * 暂停视频 */ TAG_PAUSE_VIDEO } @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); switch (newState) { case RecyclerView.SCROLL_STATE_IDLE://停止滚动 autoPlayVideo(recyclerView, VideoTagEnum.TAG_AUTO_PLAY_VIDEO); default: // autoPlayVideo(recyclerView, VideoTagEnum.TAG_PAUSE_VIDEO);//滑动时暂停视频 需要可以加上 break; } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); if (layoutManager instanceof LinearLayoutManager) { LinearLayoutManager linearManager = (LinearLayoutManager) layoutManager; firstVisibleItem = linearManager.findFirstVisibleItemPosition(); lastVisibleItem = linearManager.findLastVisibleItemPosition(); visibleCount = lastVisibleItem - firstVisibleItem; } } /** * 循环遍历 可见区域的播放器 * 然后通过 getLocalVisibleRect(rect)方法计算出哪个播放器完全显示出来 * <p> * getLocalVisibleRect相关链接:http://www.cnblogs.com/ai-developers/p/4413585.html * * @param recyclerView * @param handleVideoTag 视频需要进行状态 */ private void autoPlayVideo(RecyclerView recyclerView, VideoTagEnum handleVideoTag) { for (int i = 0; i < visibleCount; i++) { if (recyclerView != null && recyclerView.getChildAt(i) != null && recyclerView.getChildAt(i).findViewById(R.id.videoplayer) != null) { MyJzvdStd homeGSYVideoPlayer = (MyJzvdStd) recyclerView.getChildAt(i).findViewById(R.id.videoplayer); Rect rect = new Rect(); homeGSYVideoPlayer.getLocalVisibleRect(rect); int videoheight = homeGSYVideoPlayer.getHeight(); if (rect.top == 0 && rect.bottom == videoheight) { handleVideo(handleVideoTag, homeGSYVideoPlayer); // 跳出循环,只处理可见区域内的第一个播放器 break; } } } } /** * 视频状态处理 * * @param handleVideoTag 视频需要进行状态 * @param homeGSYVideoPlayer JZVideoPlayer播放器 */ private void handleVideo(VideoTagEnum handleVideoTag, MyJzvdStd homeGSYVideoPlayer) { switch (handleVideoTag) { case TAG_AUTO_PLAY_VIDEO: if ((homeGSYVideoPlayer.state != STATE_PLAYING)) { // 进行播放 homeGSYVideoPlayer.startVideo(); } break; case TAG_PAUSE_VIDEO: if ((homeGSYVideoPlayer.state != STATE_PAUSE)) { // 模拟点击,暂停视频 homeGSYVideoPlayer.startButton.performClick(); } break; default: break; } } } /** * 拦截返回键 返回不退出程序 */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (Jzvd.backPress()) { return true; } else { if (keyCode == KeyEvent.KEYCODE_BACK) { moveTaskToBack(true); return true; } } return super.onKeyDown(keyCode, event); } }

横竖屏切换时需要在界面清单文件中添加:

android:configChanges="orientation|screenSize|keyboardHidden"属性
最新回复(0)