android媒体播放框架,Android 使用超简单的多媒体播放器JiaoZiVideoPlayer
在之前的項(xiàng)目中用到了視頻播放的功能,在網(wǎng)上看了看使用了大家用的比較多的一個開源項(xiàng)目JiaoZiVideo可以迅速的實(shí)現(xiàn)視頻播放的相關(guān)功能。
JiaoZiVideo的簡單使用
集成了JiaoZiVideo后僅需這幾行代碼就可以實(shí)現(xiàn)播放視頻
JZVideoPlayerStandard jzVideoPlayerStandard = (JZVideoPlayerStandard) findViewById(R.id.jz_vedio);
//設(shè)置播放視頻鏈接和視頻標(biāo)題
jzVideoPlayerStandard.setUp(VEDIO_URL
, JZVideoPlayer.SCREEN_WINDOW_NORMAL, "餃子在哪里");
//為播放視頻設(shè)置封面圖
jzVideoPlayerStandard.thumbImageView.setImageResource(R.mipmap.ic_launcher);
Jz播放器的簡單使用,只需要在布局文件中引入該文件,然后為其設(shè)置待播放視頻的鏈接和播放視頻的封面圖即可。其它的播放相關(guān)的無需我們關(guān)心。
代碼結(jié)構(gòu)分析
image.png
JiaoZiVideo主要特點(diǎn)
可以完全自定義UI和任何功能
可以完全自定義UI和任何功能
一行代碼切換播放引擎,支持的視頻格式和協(xié)議取決于播放引擎,android.media.MediaPlayer ijkplayer
完美檢測列表滑動
可實(shí)現(xiàn)全屏播放,小窗播放
能在ListView、ViewPager和ListView、ViewPager和Fragment等多重嵌套模式下全屏工作
可以在加載、暫停、播放等各種狀態(tài)中正常進(jìn)入全屏和退出全屏
多種視頻適配屏幕的方式,可鋪滿全屏,可以全屏剪裁
重力感應(yīng)自動進(jìn)入全屏
全屏后手勢修改進(jìn)度和音量
Home鍵退出界面暫停播放,返回界面繼續(xù)播放
JiaoZiVideo的使用指南
1..添加類庫
implementation 'cn.jzvd:jiaozivideoplayer:7.0.3'
2.添加布局
android:layout_width="match_parent"
android:layout_height="200dp">
android:id="@+id/jz_video"
android:layout_width="match_parent"
android:layout_height="200dp" />
3.設(shè)置視頻地址、縮略圖地址、標(biāo)題
MyJzvdStd jzvdStd = (MyJzvdStd) findViewById(R.id.jz_video);
jzvdStd.setUp("http://jzvd.nathen.cn/c6e3dc12a1154626b3476d9bf3bd7266/6b56c5f0dc31428083757a45764763b0-5287d2089db37e62345123a1be272f8b.mp4"
, "餃子閉眼睛");
jzvdStd.thumbImageView.setImage("http://p.qpic.cn/videoyun/0/2449_43b6f696980311e59ed467f22794e792_1/640");
4.在Activity中
@Override
public void onBackPressed() {
if (Jzvd.backPress()) {
return;
}
super.onBackPressed();
}
@Override
protected void onPause() {
super.onPause();
Jzvd.releaseAllVideos();
}
5.在AndroidManifest.xml中
android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="portrait" />
以上只是簡單的播放視頻功能,但是大家的項(xiàng)目需求里應(yīng)該不僅僅只是需要播放視頻就好了,所以下面寫一下還有哪些常規(guī)使用方法
Glide.with(this).load(Url).into(myJzvdStd.thumbImageView); //推薦使用Glide
自動播放有兩種 這里隨便選擇添加一個,
1. myJzvdStd.startButton.performClick();
2. myJzvdStd.startVideo();
//這里只有開始播放時才生效
mJzvdStd.seekToInAdvance = 20000;
//跳轉(zhuǎn)制定位置播放
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, );
這里很多人問為什么播不了,請認(rèn)真怒url,播不了就是url沒怒對
復(fù)制Demo中CustomMediaPlayerAssertFolder類到你的項(xiàng)目下
----------------------------------------------------------------------------
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());//進(jìn)入此頁面修改MediaInterface,讓此頁面的jzvd正常工作
JzvdStd.startFullscreen(this, JzvdStd.class, VideoConstant.videoUrlList[6], "餃子辛苦了");
mJzvdStd.startWindowTiny();
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();
}
}
}
});
創(chuàng)建一個類繼承JzvdStd并在XML設(shè)置
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);
}
}
/**
* 進(jìn)入全屏模式的時候關(guān)閉靜音模式
*/
@Override
public void startWindowFullscreen() {
super.startWindowFullscreen();
JZMediaManager.instance().jzMediaInterface.setVolume(1f, 1f);
}
/**
* 退出全屏模式的時候開啟靜音模式
*/
@Override
public void playOnThisJzvd() {
super.playOnThisJzvd();
JZMediaManager.instance().jzMediaInterface.setVolume(0f, 0f);
}
}
創(chuàng)建一個類繼承JzvdStd并在XML設(shè)置
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();
}
}
}
復(fù)制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);
}
}
}
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);
}
}
@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("標(biāo)清", 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);
創(chuàng)建一個類集成JzvdStd并在XML設(shè)置
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循環(huán)標(biāo)志
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;
Jzvd.WIFI_TIP_DIALOG_SHOWED=true;
Jzvd.clearSavedProgress(this, "url");
ijk
復(fù)制Demo中JZMediaIjkplayer類到你的項(xiàng)目下
implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.4'
implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4'
Jzvd.setMediaInterface(new JZMediaIjkplayer()); // ijkMediaPlayer
Mediaplayer
Jzvd.setMediaInterface(new JZMediaSystem()); //
exo
復(fù)制Demo中JZExoPlayer類到你的項(xiàng)目下
implementation 'com.google.android.exoplayer:exoplayer:2.7.1'
Jzvd.setMediaInterface(new JZExoPlayer()); //exo
Jzvd.setJzUserAction(new MyUserActionStd());
/**
* 這只是給埋點(diǎn)統(tǒng)計(jì)用戶數(shù)據(jù)用的,不能寫和播放相關(guān)的邏輯,監(jiān)聽事件請參考MyJzvdStd,復(fù)寫函數(shù)取得相應(yīng)事件
*/
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;
}
}
}
相關(guān)函數(shù)回調(diào),屏幕狀態(tài),播放器狀態(tài),事件
在繼承JzvdStd之后,可以通過父類的mCurrentState,取得當(dāng)前的播放狀態(tài)。
CURRENT_STATE_IDLE 未知狀態(tài),指控件被new出來之后什么都沒做
CURRENT_STATE_NORMAL 普通狀態(tài)
CURRENT_STATE_PREPARING 視頻準(zhǔn)備狀態(tài)
CURRENT_STATE_PREPARING_CHANGING_URL 播放中切換url的準(zhǔn)備狀態(tài)
CURRENT_STATE_PLAYING 播放中狀態(tài)
CURRENT_STATE_PAUSE 暫停狀態(tài)
CURRENT_STATE_AUTO_COMPLETE 自動播放完成狀態(tài)
CURRENT_STATE_ERROR 錯誤狀態(tài)
復(fù)寫進(jìn)入播放狀態(tài)的函數(shù),取得播放狀態(tài)的回調(diào)
onStateNormal 進(jìn)入普通狀態(tài),通常指setUp之后
onStatePreparing 進(jìn)入準(zhǔn)備中狀態(tài),就是loading狀態(tài)
onStatePlaying 進(jìn)入播放狀態(tài)
onStatePause 進(jìn)入暫停狀態(tài)
onStateError 進(jìn)入錯誤狀態(tài)
onStateAutoComplete 進(jìn)入自動播放完成狀態(tài)
全屏、小窗、非全屏分別是不同的實(shí)例,在繼承JzvdStd后,通過mCurrentScreen變量,取得當(dāng)前屏幕類型
SCREEN_WINDOW_NORMAL 普通窗口(進(jìn)入全屏之前的)
SCREEN_WINDOW_LIST 列表窗口(進(jìn)入全屏之前)
SCREEN_WINDOW_FULLSCREEN 全屏
SCREEN_WINDOW_TINY 小窗
事件
復(fù)寫onProgress函數(shù),取得每次播放器設(shè)置底部seekBar的進(jìn)度回調(diào)
調(diào)用changeUrl函數(shù),切換url
復(fù)寫onClick函數(shù),取得各種按鈕的點(diǎn)擊事件
復(fù)寫onTouch函數(shù),取得全屏之后的手勢操作
JiaoZiVideoPlayer的功能遠(yuǎn)不止上述這些,最近我也在深入的研究中,下篇文章會收集一些大家經(jīng)常遇到的問題寫出來幫助大家,大家有什么建議或者問題可以再下方留言。
總結(jié)
以上是生活随笔為你收集整理的android媒体播放框架,Android 使用超简单的多媒体播放器JiaoZiVideoPlayer的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 加油卡多少钱啊?
- 下一篇: ios html清除缓存图片,iOS,如