主要特点
可以完全自定义UI和任何功能
一行代码切换播放引擎,支持的视频格式和协议取决于播放引擎,android.media.MediaPlayer ijkplayer
完美检测列表滑动
可实现全屏播放,小窗播放
能在ListView、ViewPager和ListView、ViewPager和Fragment等多重嵌套模式下全屏工作
可以在加载、暂停、播放等各种状态中正常进入全屏和退出全屏
多种视频适配屏幕的方式,可铺满全屏,可以全屏剪裁
重力感应自动进入全屏
全屏后手势修改进度和音量
Home键退出界面暂停播放,返回界面继续播放
WebView嵌套本地视频控件
demo中添加视频缓存的例子
集成使用
即便是自定义UI,或者对Library有过修改,也是这五步骤来使用播放器。
1.添加类库
compile 'cn.jzvd:jiaozivideoplayer:release'
2.添加布局
<cn.jzvd.JzvdStd android:id="@+id/videoplayer" android:layout_width="match_parent" android:layout_height="200dp"/>
3.设置视频地址、缩略图地址、标题
MyJzvdStd myJzvdStd= findViewById(R.id.videoplayer); myJzvdStd.setUp("http://jzvd.nathen.cn/342a5f7ef6124a4a8faf00e738b8bee4/cf6d9db0bd4d41f59d09ea0a81e918fd-5287d2089db37e62345123a1be272f8b.mp4" , "饺子快长大", JzvdStd.SCREEN_WINDOW_NORMAL); Glide.with(this).load("http://jzvd-pic.nathen.cn/jzvd-pic/1bb2ebbe-140d-4e2e-abd2-9e7e564f71ac.png").into(myJzvdStd.thumbImageView);
4.在Activity中
@Override protected void onPause() { super.onPause(); Jzvd.releaseAllVideos(); } @Override public void onBackPressed() { if (Jzvd.backPress()) { return; } super.onBackPressed(); }
在AndroidManifest.xml中
<activity android:name=".MainActivity" android:configChanges="orientation|screenSize|keyboardHidden" android:screenOrientation="portrait" /> <!-- or android:screenOrientation="landscape"-->
基本使用
加缩略载图
Glide.with(this).load(Url).into(myJzvdStd.thumbImageView); //推荐使用Glide
自动播放
1. myJzvdStd.startButton.performClick(); 2. myJzvdStd.startVideo();
跳转制定位置播放
//这里只有开始播放时才生效mJzvdStd.seekToInAdvance = 20000;//跳转制定位置播放JZMediaManager.seekTo(30000);
2.播放sd卡下视频
public void cpAssertVideoToLocalPath() { try { InputStream myInput; OutputStream myOutput = new FileOutputStream(Environment.getExternalStorageDirectory().getAbsolutePath() + "/DCIM/Camera/local_video.mp4"); myInput = this.getAssets().open("local_video.mp4"); byte[] buffer = new byte[1024]; int length = myInput.read(buffer); while (length > 0) { myOutput.write(buffer, 0, length); length = myInput.read(buffer); } myOutput.flush(); myInput.close(); myOutput.close(); } catch (IOException e) { e.printStackTrace(); } } myJzvdStd.setUp(Environment.getExternalStorageDirectory().getAbsolutePath() + "/DCIM/Camera/local_video.mp4", "饺子不信",Jzvd.SCREEN_WINDOW_NORMAL, ); 这里很多人问为什么播不了,请认真怒url,播不了就是url没怒对
播放assets目录下的视频
复制Demo中CustomMediaPlayerAssertFolder类到你的项目下 ---------------------------------------------------------------------------- JZDataSource jzDataSource = null; try { jzDataSource = new JZDataSource(getAssets().openFd("local_video.mp4")); jzDataSource.title = "饺子快长大"; } catch (IOException e) { e.printStackTrace(); } jzvdStd.setUp(jzDataSource, JzvdStd.SCREEN_WINDOW_NORMAL); Glide.with(this) .load("http://jzvd-pic.nathen.cn/jzvd-pic/1bb2ebbe-140d-4e2e-abd2-9e7e564f71ac.png") .into(jzvdStd.thumbImageView); Jzvd.setMediaInterface(new CustomMediaPlayerAssertFolder());//进入此页面修改MediaInterface,让此页面的jzvd正常工作
直接全屏播放
JzvdStd.startFullscreen(this, JzvdStd.class, VideoConstant.videoUrlList[6], "饺子辛苦了");
开启小窗播放
mJzvdStd.startWindowTiny();
列表Item划出开启小窗播放
1.Listview listView.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { Jzvd.onScrollAutoTiny(view, firstVisibleItem, visibleItemCount, totalItemCount); // Jzvd.onScrollReleaseAllVideos(view, firstVisibleItem, visibleItemCount, totalItemCount); 这是不开启列表划出小窗 同时也是画出屏幕释放JZ 划出暂停 } });2. RecyclerView 划出列表开启小窗 recyclerView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() { @Override public void onChildViewAttachedToWindow(View view) { Jzvd.onChildViewAttachedToWindow(view, R.id.videoplayer); } @Override public void onChildViewDetachedFromWindow(View view) { Jzvd.onChildViewDetachedFromWindow(view); } });2.1 RecyclerView划出屏幕释放JZ,同时也是不开启列表划出显示小窗 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.jzDataSource.containsTheUrl(JZMediaManager.getCurrentUrl())) { Jzvd currentJzvd = JzvdMgr.getCurrentJzvd(); if (currentJzvd != null && currentJzvd.currentScreen != Jzvd.SCREEN_WINDOW_FULLSCREEN) { Jzvd.releaseAllVideos(); } } } });
小屏播放无声音,全屏有声音
创建一个类继承JzvdStd并在XML设置public class JzvdStdVolumeAfterFullscreen extends JzvdStd { public JzvdStdVolumeAfterFullscreen(Context context) { super(context); } public JzvdStdVolumeAfterFullscreen(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void onPrepared() { super.onPrepared(); if (currentScreen == SCREEN_WINDOW_FULLSCREEN) { JZMediaManager.instance().jzMediaInterface.setVolume(1f, 1f); } else { JZMediaManager.instance().jzMediaInterface.setVolume(0f, 0f); } } /** * 进入全屏模式的时候关闭静音模式 */ @Override public void startWindowFullscreen() { super.startWindowFullscreen(); JZMediaManager.instance().jzMediaInterface.setVolume(1f, 1f); } /** * 退出全屏模式的时候开启静音模式 */ @Override public void playOnThisJzvd() { super.playOnThisJzvd(); JZMediaManager.instance().jzMediaInterface.setVolume(0f, 0f); } }
全屏状态播放完成,不退出全屏
创建一个类继承JzvdStd并在XML设置public class JzvdStdAutoCompleteAfterFullscreen extends JzvdStd { public JzvdStdAutoCompleteAfterFullscreen(Context context) { super(context); } public JzvdStdAutoCompleteAfterFullscreen(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void startVideo() { if (currentScreen == SCREEN_WINDOW_FULLSCREEN) { Log.d(TAG, "startVideo [" + this.hashCode() + "] "); initTextureView(); addTextureView(); AudioManager mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); mAudioManager.requestAudioFocus(onAudioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); JZUtils.scanForActivity(getContext()).getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); JZMediaManager.setDataSource(jzDataSource); JZMediaManager.instance().positionInList = positionInList; onStatePreparing(); } else { super.startVideo(); } } @Override public void onAutoCompletion() { if (currentScreen == SCREEN_WINDOW_FULLSCREEN) { onStateAutoComplete(); } else { super.onAutoCompletion(); } } }
全屏模式下显示分享按钮
复制DEMO下的layout文件在 layout_top 布局下 添加你的分享按钮public class JzvdStdShowShareButtonAfterFullscreen extends JzvdStd { public ImageView shareButton; public JzvdStdShowShareButtonAfterFullscreen(Context context) { super(context); } public JzvdStdShowShareButtonAfterFullscreen(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void init(Context context) { super.init(context); shareButton = findViewById(R.id.share); shareButton.setOnClickListener(this); } @Override public int getLayoutId() { return R.layout.layout_standard_with_share_button; } @Override public void onClick(View v) { super.onClick(v); if (v.getId() == R.id.share) { Toast.makeText(getContext(), "Whatever the icon means", Toast.LENGTH_SHORT).show(); } } @Override public void setUp(JZDataSource jzDataSource, int screen) { super.setUp(jzDataSource, screen); if (currentScreen == SCREEN_WINDOW_FULLSCREEN) { shareButton.setVisibility(View.VISIBLE); } else { shareButton.setVisibility(View.INVISIBLE); } } }
小屏状态下不显示标题,全屏模式下显示标题
public class JzvdStdShowTitleAfterFullscreen extends JzvdStd { public JzvdStdShowTitleAfterFullscreen(Context context) { super(context); } public JzvdStdShowTitleAfterFullscreen(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void setUp(JZDataSource jzDataSource, int screen) { super.setUp(jzDataSource, screen); if (currentScreen == SCREEN_WINDOW_FULLSCREEN) { titleTextView.setVisibility(View.VISIBLE); } else { titleTextView.setVisibility(View.INVISIBLE); } } }
播放MP3
public class JzvdStdMp3 extends JzvdStd { public JzvdStdMp3(Context context) { super(context); } public JzvdStdMp3(Context context, AttributeSet attrs) { super(context, attrs); } @Override public int getLayoutId() { return R.layout.jz_layout_standard_mp3; } @Override public void onClick(View v) { if (v.getId() == cn.jzvd.R.id.thumb && (currentState == CURRENT_STATE_PLAYING || currentState == CURRENT_STATE_PAUSE)) { onClickUiToggle(); } else if (v.getId() == R.id.fullscreen) { } else { super.onClick(v); } } //changeUiTo 真能能修改ui的方法 @Override public void changeUiToNormal() { super.changeUiToNormal(); } @Override public void changeUiToPreparing() { super.changeUiToPreparing(); } @Override public void changeUiToPlayingShow() { super.changeUiToPlayingShow(); thumbImageView.setVisibility(View.VISIBLE); } @Override public void changeUiToPlayingClear() { super.changeUiToPlayingClear(); thumbImageView.setVisibility(View.VISIBLE); } @Override public void changeUiToPauseShow() { super.changeUiToPauseShow(); thumbImageView.setVisibility(View.VISIBLE); } @Override public void changeUiToPauseClear() { super.changeUiToPauseClear(); thumbImageView.setVisibility(View.VISIBLE); } @Override public void changeUiToComplete() { super.changeUiToComplete(); } @Override public void changeUiToError() { super.changeUiToError(); } } jzvdStdMp3 = findViewById(R.id.jz_videoplayer_mp3); jzvdStdMp3.setUp(URL, "饺子摇摆", Jzvd.SCREEN_WINDOW_NORMAL); Glide.with(this) .load(VideoConstant.videoThumbs[0][1]) .into(jzvdStdMp3.thumbImageView);
播放完成不显示预览图
public class JzvdStdShowTextureViewAfterAutoComplete extends JzvdStd { public JzvdStdShowTextureViewAfterAutoComplete(Context context) { super(context); } public JzvdStdShowTextureViewAfterAutoComplete(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void onAutoCompletion() { super.onAutoCompletion(); thumbImageView.setVisibility(View.GONE); } }
Home键退出界面暂停播放,返回界面继续播放
@Override protected void onResume() { super.onResume(); //home back JzvdStd.goOnPlayOnResume(); } @Override protected void onPause() { super.onPause(); // Jzvd.clearSavedProgress(this, null); //home back JzvdStd.goOnPlayOnPause(); }
边播边缓存和清晰度切换
1. 集成videocache implementation 'com.danikula:videocache:2.7.0',并初始化public class ApplicationDemo extends Application { @Override public void onCreate() { super.onCreate();// LeakCanary.install(this); } private HttpProxyCacheServer proxy; public static HttpProxyCacheServer getProxy(Context context) { ApplicationDemo app = (ApplicationDemo) context.getApplicationContext(); return app.proxy == null ? (app.proxy = app.newProxy()) : app.proxy; } private HttpProxyCacheServer newProxy() { return new HttpProxyCacheServer(this); } }2.引用 LinkedHashMap map = new LinkedHashMap(); String proxyUrl = ApplicationDemo.getProxy(this).getProxyUrl(VideoConstant.videoUrls[0][9]); map.put("高清", proxyUrl); map.put("标清", VideoConstant.videoUrls[0][6]); map.put("普清", VideoConstant.videoUrlList[0]); JZDataSource jzDataSource = new JZDataSource(map, "饺子不信"); jzDataSource.looping = true; jzDataSource.currentUrlIndex = 2; jzDataSource.headerMap.put("key", "value");//header mJzvdStd.setUp(jzDataSource , JzvdStd.SCREEN_WINDOW_NORMAL); Glide.with(this).load(VideoConstant.videoThumbList[0]).into(mJzvdStd.thumbImageView);
重复播放
创建一个类集成JzvdStd并在XML设置public class JZVideoPlayerStandardLoopVideo extends JzvdStd{ public JZVideoPlayerStandardLoopVideo (Context context) { super(context); } public JZVideoPlayerStandardLoopVideo (Context context, AttributeSet attrs) { super(context, attrs); } @Override public void onAutoCompletion() { super.onAutoCompletion(); startVideo(); } } 还有一种方法就是上面清晰度切换loop循环标志
重力感应自动进入全屏
SensorManager mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); Jzvd.JZAutoFullscreenListener mSensorEventListener = new Jzvd.JZAutoFullscreenListener(); @Override protected void onResume() { super.onResume(); Sensor accelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); mSensorManager.registerListener(mSensorEventListener, accelerometerSensor, SensorManager.SENSOR_DELAY_NORMAL); } @Override protected void onPause() { super.onPause(); mSensorManager.unregisterListener(mSensorEventListener); }
重力感应
Jzvd.FULLSCREEN_ORIENTATION=ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; Jzvd.NORMAL_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; 两个变量控制全屏前后的屏幕方向
不保存播放进度
Jzvd.SAVE_PROGRESS = false;
取消播放时在非WIFIDialog提示
Jzvd.WIFI_TIP_DIALOG_SHOWED=true;
清除某个URL进度
Jzvd.clearSavedProgress(this, "url");
获取视频某一帧
/** * context 上下文 * uri 视频地址 * imageView 设置image * frameTimeMicros 获取某一时间帧 */public static void loadVideoScreenshot(final Context context, String uri, ImageView imageView, long frameTimeMicros) { RequestOptions requestOptions = RequestOptions.frameOf(frameTimeMicros); requestOptions.set(FRAME_OPTION, MediaMetadataRetriever.OPTION_CLOSEST); requestOptions.transform(new BitmapTransformation() { @Override protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) { return toTransform; } @Override public void updateDiskCacheKey(MessageDigest messageDigest) { try { messageDigest.update((context.getPackageName() + "RotateTransform").getBytes("utf-8")); } catch (Exception e) { e.printStackTrace(); } } }); Glide.with(context).load(uri).apply(requestOptions).into(imageView); }
切换播放内核
ijk 复制Demo中JZMediaIjkplayer类到你的项目下 implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.4' implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4' Jzvd.setMediaInterface(new JZMediaIjkplayer()); // ijkMediaPlayerMediaplayer Jzvd.setMediaInterface(new JZMediaSystem()); // exo 复制Demo中JZExoPlayer类到你的项目下 implementation 'com.google.android.exoplayer:exoplayer:2.7.1' Jzvd.setMediaInterface(new JZExoPlayer()); //exo
用户埋点统计
Jzvd.setJzUserAction(new MyUserActionStd()); /** * 这只是给埋点统计用户数据用的,不能写和播放相关的逻辑,监听事件请参考MyJzvdStd,复写函数取得相应事件 */ class MyUserActionStd implements JZUserActionStd { @Override public void onEvent(int type, Object url, int screen, Object... objects) { switch (type) { case JZUserAction.ON_CLICK_START_ICON: Log.i("USER_EVENT", "ON_CLICK_START_ICON" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen); break; case JZUserAction.ON_CLICK_START_ERROR: Log.i("USER_EVENT", "ON_CLICK_START_ERROR" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen); break; case JZUserAction.ON_CLICK_START_AUTO_COMPLETE: Log.i("USER_EVENT", "ON_CLICK_START_AUTO_COMPLETE" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen); break; case JZUserAction.ON_CLICK_PAUSE: Log.i("USER_EVENT", "ON_CLICK_PAUSE" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen); break; case JZUserAction.ON_CLICK_RESUME: Log.i("USER_EVENT", "ON_CLICK_RESUME" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen); break; case JZUserAction.ON_SEEK_POSITION: Log.i("USER_EVENT", "ON_SEEK_POSITION" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen); break; case JZUserAction.ON_AUTO_COMPLETE: Log.i("USER_EVENT", "ON_AUTO_COMPLETE" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen); break; case JZUserAction.ON_ENTER_FULLSCREEN: Log.i("USER_EVENT", "ON_ENTER_FULLSCREEN" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen); break; case JZUserAction.ON_QUIT_FULLSCREEN: Log.i("USER_EVENT", "ON_QUIT_FULLSCREEN" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen); break; case JZUserAction.ON_ENTER_TINYSCREEN: Log.i("USER_EVENT", "ON_ENTER_TINYSCREEN" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen); break; case JZUserAction.ON_QUIT_TINYSCREEN: Log.i("USER_EVENT", "ON_QUIT_TINYSCREEN" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen); break; case JZUserAction.ON_TOUCH_SCREEN_SEEK_VOLUME: Log.i("USER_EVENT", "ON_TOUCH_SCREEN_SEEK_VOLUME" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen); break; case JZUserAction.ON_TOUCH_SCREEN_SEEK_POSITION: Log.i("USER_EVENT", "ON_TOUCH_SCREEN_SEEK_POSITION" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen); break; case JZUserActionStd.ON_CLICK_START_THUMB: Log.i("USER_EVENT", "ON_CLICK_START_THUMB" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen); break; case JZUserActionStd.ON_CLICK_BLANK: Log.i("USER_EVENT", "ON_CLICK_BLANK" + " title is : " + (objects.length == 0 ? "" : objects[0]) + " url is : " + url + " screen is : " + screen); break; default: Log.i("USER_EVENT", "unknow"); break; } } }
相关函数回调,屏幕状态,播放器状态,事件
继承JzvdStd之后,可以通过父类的mCurrentState,取得当前的播放状态。
CURRENT_STATE_IDLE 未知状态,指控件被new出来之后什么都没做
CURRENT_STATE_NORMAL 普通状态
CURRENT_STATE_PREPARING 视频准备状态
CURRENT_STATE_PREPARING_CHANGING_URL 播放中切换url的准备状态
CURRENT_STATE_PLAYING 播放中状态
CURRENT_STATE_PAUSE 暂停状态
CURRENT_STATE_AUTO_COMPLETE 自动播放完成状态
CURRENT_STATE_ERROR 错误状态
复写进入播放状态的函数,取得播放状态的回调
onStateNormal 进入普通状态,通常指setUp之后
onStatePreparing 进入准备中状态,就是loading状态
onStatePlaying 进入播放状态
onStatePause 进入暂停状态
onStateError 进入错误状态
onStateAutoComplete 进入自动播放完成状态
了解当前屏幕类型
全屏、小窗、非全屏分别是不同的实例,在继承JzvdStd后,通过mCurrentScreen变量,取得当前屏幕类型
SCREEN_WINDOW_NORMAL 普通窗口(进入全屏之前的)
SCREEN_WINDOW_LIST 列表窗口(进入全屏之前)
SCREEN_WINDOW_FULLSCREEN 全屏
SCREEN_WINDOW_TINY 小窗
事件
复写onProgress函数,取得每次播放器设置底部seekBar的进度回调
调用changeUrl函数,切换url
复写onClick函数,取得各种按钮的点击事件
复写onTouch函数,取得全屏之后的手势操作
一些需求实现(以下实现都是本人的思考逻辑和借鉴一些网络,不完善,要根据你自己项目实际情况来)
1.会员试看功能
首先从思路上理清步骤
首先拿到当前播放时间和是试看时间做判断(考虑拖动进度条超过试看时间)
从后台拿到特定字段判断是否付费
弹出试看结束功能Dialog
付费完回来继续播放(省去付费步骤)———取消
根据自己项目的实际情况来 ,这里只是简单的测试public class TryToSeeVideo extends JzvdStd { RelativeLayout mRelativeLayout; TextView mExit, mPay, mTryToSee; boolean isNoPay; public TryToSeeVideo(Context context) { super(context); } public TryToSeeVideo(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void init(Context context) { super.init(context); mRelativeLayout = findViewById(R.id.try_to_see_tip); mExit = findViewById(R.id.exit); //退出按钮 mPay = findViewById(R.id.pay); //支付按钮 mTryToSee = findViewById(R.id.try_see); //重新试看按钮 mExit.setOnClickListener(this); mPay.setOnClickListener(this); mTryToSee.setOnClickListener(this); } @Override public int getLayoutId() { return R.layout.try_to_see_video_layout; } @Override public void onClick(View v) { super.onClick(v); switch (v.getId()) { case R.id.exit: //finish界面 建议回调出当前事件 break; case R.id.pay: //进入支付界面 支付成功后 Jzvd.goOnPlayOnResume(); getContext().startActivity(new Intent(getContext(), ActivityMain.class)); //模拟跳转支付界面 break; case R.id.try_see: JZMediaManager.seekTo(0);//回到0秒 Jzvd.goOnPlayOnResume(); progressBar.setProgress(0); mRelativeLayout.setVisibility(GONE); break; } } /** * @param progress 百分比 * @param position 当前时间 * @param duration 总时长 */ @Override public void onProgress(int progress, long position, long duration) { super.onProgress(progress, position, duration); long totalSeconds = position / 1000; if (true) { //这里是从服务器拿到特定字段判断是否付费 这里模拟未付费 if (totalSeconds >= 30) { //考虑未付费情况下拖动进度条超过试看时间 if (!isNoPay) { //加个标记 因为此函数一直在回调 JZMediaManager.seekTo(30000); //回到30秒 progressBar.setProgress(30); mRelativeLayout.setVisibility(VISIBLE); //在适当的时候隐藏 Jzvd.goOnPlayOnPause(); //在适当的时候(支付成功后)播放 startButton.setEnabled(false); //在适当的时候取消 isNoPay = true; } } } } @Override public void onStatePlaying() { super.onStatePlaying(); isNoPay = false; startButton.setEnabled(true); } }
2.列表页到详情页无时差播放
3.列表自动播放
4.自动播放下一集剧集
函数 changeUrl 三个重载 根据自己的实际情况来
changeUrl(String url, String title, long seekToInAdvance) //seekToInAdvance 时间
changeUrl(JZDataSource jzDataSource, long seekToInAdvance)
changeUrl(int urlMapIndex, long seekToInAdvance)
这里是演示自动播放下一集(如果要自己选集,自定义UI定义出剧集列表,调用上面三个任意一个)
public class AutoPlayNextVideo extends JzvdStd { int UrlIndex = 0; //剧集标识 public AutoPlayNextVideo(Context context) { super(context); } public AutoPlayNextVideo(Context context, AttributeSet attrs) { super(context, attrs); } /** * 自动播放下一集 * 若果需要手动选集 自定义Ui定义出剧集列表 调用相关changeUrl */ @Override public void onAutoCompletion() { super.onAutoCompletion(); if (UrlIndex<videoUrlList.length){ UrlIndex++; changeUrl(videoUrlList[UrlIndex], "各剧集的标题", 0); } } }
作者:大明小明C
链接:https://www.jianshu.com/p/4c187a09b838