接着上一篇文章 Vitamio库打造万能播放器(三)
终于到了介绍vitamio的使用了,这个库使用起来非常简单,很容易上手,只需要将前面我们创建好的VideoPlayerActivity的VideoView相关的api的包名换一下即可,无需改动其他代码如下所示:
package mchenys.net.csdn.blog.myplayer.module.video; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.media.AudioManager; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.text.format.DateFormat; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.SeekBar; import android.widget.TextView; import java.util.List; import io.vov.vitamio.LibsChecker; import io.vov.vitamio.MediaPlayer; import io.vov.vitamio.widget.VideoView; import mchenys.net.csdn.blog.myplayer.R; import mchenys.net.csdn.blog.myplayer.common.base.BaseActivity; import mchenys.net.csdn.blog.myplayer.common.config.Constant; import mchenys.net.csdn.blog.myplayer.common.model.Video; import mchenys.net.csdn.blog.myplayer.common.utils.LogUtils; import mchenys.net.csdn.blog.myplayer.common.utils.TimeUtils; import mchenys.net.csdn.blog.myplayer.common.utils.UIUtils; import mchenys.net.csdn.blog.myplayer.common.widget.TitleBar; import mchenys.net.csdn.blog.myplayer.common.widget.nineoldandroids.view.ViewHelper; import mchenys.net.csdn.blog.myplayer.common.widget.nineoldandroids.view.ViewPropertyAnimator; /** * Vitamio 万能视频播放器 * 直接从VideoPlayerActivity修改Copy过来,关于VideoView的api完全一样,只是导包不一样. * 1.多了这一句 if (!LibsChecker.checkVitamioLibs(this)) return; 以及内部的VideoView对全屏和按比例缩放的代码处理方式不一样 * 2.布局文件换成了activity_video_player_vitamio * Created by mChenys on 2016/1/17. */ public class VitamioVideoPlayerActivity extends BaseActivity { private VideoView mVideoView; private int mPosition; private List<Video> mVideoList; private ImageButton mBackIb, mPreIb, mNextIb, mPlayIb, mFullScreenIb, mVolumeIb; private TextView mTitleTv, mSysTimeTv, mCurrVideoPositionTv, mVideoDurationTv; private ImageView mBatteryIv; private View mBrightnessView; private LinearLayout mTopControlLl, mBottomControlLl; private Handler mHandler; private AudioManager mAudioManager; private int mMaxVolume, mCurrVolume; private SeekBar mVolumeSb, mVideoSb; private GestureDetector mGestureDetector; private float mVolumeScreenHeightScale; private float mCurrBrightness; private boolean mIsLeftDown; private float mBrightnessScreenHeightScale; private Video mVideo; @Override protected void setTitleBar(TitleBar titleBar) { titleBar.setVisibility(View.GONE); } @Override protected boolean isHomePage() { return false; } @Override public Integer getLayoutResId() { return R.layout.activity_video_player_vitamio; } @Override public void initView() { mVideoView = findView(R.id.videoView); mTitleTv = findView(R.id.tv_title);//标题 mSysTimeTv = findView(R.id.tv_system_time);//系统时间 mCurrVideoPositionTv = findView(R.id.tv_current_position);//当前播放位置 mVideoDurationTv = findView(R.id.tv_duration);//视频时长 mVolumeIb = findView(R.id.ib_voice);//静音 mBackIb = findView(R.id.ib_back);//返回 mPreIb = findView(R.id.ib_pre);//上一首 mPlayIb = findView(R.id.ib_play);//播放 mNextIb = findView(R.id.ib_next);//下一首 mFullScreenIb = findView(R.id.ib_fullScreen);//全屏 mBatteryIv = findView(R.id.iv_battery);//电量 mVolumeSb = findView(R.id.sb_voice);//音量进度seekBar mVideoSb = findView(R.id.sb_video);//视频进度seekBar mBrightnessView = findView(R.id.view_brightness);//通过透明度改变屏幕亮度的view //默认隐藏控制面板 mTopControlLl = findView(R.id.ll_top_ctrl);//顶部控制面板 mBottomControlLl = findView(R.id.ll_bottom_ctrl);//底部控制面板 } @Override public void initListener() { //设置视频准备监听器 mVideoView.setOnPreparedListener(mOnPreparedListener); //设置视频播放完毕的监听器 mVideoView.setOnCompletionListener(mOnCompletionListener); //设置音量改变的seekBar监听器 mVolumeSb.setOnSeekBarChangeListener(mVolumeSeekBarChangeListener); //设置视频进度改变的seekBar监听器 mVideoSb.setOnSeekBarChangeListener(mVideoSeekBarChangeListener); //设置缓冲监听 mVideoView.setOnBufferingUpdateListener(mOnBufferingUpdateListener); //设置视频卡顿监听器 mVideoView.setOnInfoListener(mOnInfoListener); } @Override public void initData() { //注册电量接收器 registerBatteryReceiver(); // 检查Vitamio插件是否安装 if (!LibsChecker.checkVitamioLibs(this)) return; mHandler = new Handler(); Uri videoUri = getIntent().getData(); if (null != videoUri) { // 说明是从第三方应用跳转过来的 mLoadView.setProgressBarVisiable(true); mVideoView.setVideoURI(videoUri); mTitleTv.setText(videoUri.getPath()); mPreIb.setEnabled(false); mNextIb.setEnabled(false); } else { //说明是从播放列表进入的 Bundle bundle = getIntent().getExtras(); if (null == bundle || bundle.size() < 0) { mLoadView.setExceptionViewVisible(true); return; } mPosition = bundle.getInt(Constant.KEY_POSITION); mVideoList = bundle.getParcelableArrayList(Constant.KEY_LIST); //设置当前播放的视频 setCurrPlayVideo(); } //初始化音量 initVolume(); //初始化手势监听器 initGestures(); //初始化亮度值 initBrightness(); } @Override public void reLoadData() { } /** * 设置当前播放的视频 */ private void setCurrPlayVideo() { if (mVideoList == null || mVideoList.isEmpty() || mPosition == -1) { return; } mLoadView.setProgressBarVisiable(true); LogUtils.i(this, "mPosition:" + mPosition + " mVideoList:" + mVideoList); //设置上一个/下一个按钮不可用时的背景图片 mPreIb.setEnabled(mPosition != 0);//当前不是第一个,则可点击上一个 mNextIb.setEnabled(mPosition != mVideoList.size() - 1);//当前不是最后一个,则可以点击下一个 //从列表中取出要播放的视频 mVideo = mVideoList.get(mPosition); //设置播放的地址 mVideoView.setVideoPath(mVideo.path); } /** * 初始化亮度值 */ private void initBrightness() { mBrightnessView.setVisibility(View.VISIBLE); ViewHelper.setAlpha(mBrightnessView, 0f);//一开始完全透明 mBrightnessScreenHeightScale = 1.0f / UIUtils.getScreenHeight();//透明度和屏幕高度的比例 } /** * 初始化手势监听器 */ private void initGestures() { //手势监听器 mGestureDetector = new GestureDetector(this, mOnGestureListener); //最大音量和屏幕高度的比例 mVolumeScreenHeightScale = mMaxVolume * 1.0f / UIUtils.getScreenHeight(); LogUtils.i(VitamioVideoPlayerActivity.this, "mVolumeScreenHeightScale:" + mVolumeScreenHeightScale + " mMaxVolume:" + mMaxVolume + " Env.screenHeight:" + UIUtils.getScreenHeight()); } /** * 注册电量变化的接收器 */ private void registerBatteryReceiver() { IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); registerReceiver(mBatteryChangeReceiver, filter); } /** * 初始化音量控制 */ private void initVolume() { mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE); mMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);//最大音量 mCurrVolume = getStreamVolume();//当前音量 mVolumeSb.setMax(mMaxVolume); mVolumeSb.setProgress(mCurrVolume); } /** * 获取当前音量 * * @return */ private int getStreamVolume() { return mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); } /** * 更新系统音量进度 */ private void updateVolumePosition(int progress) { int streamType = AudioManager.STREAM_MUSIC; int flags = 0; //0:不显示系统音量面板,1:显示 mAudioManager.setStreamVolume(streamType, progress, flags); } /** * 切换音量 */ private void toggleVolume() { if (getStreamVolume() > 0) { //设置为静音 mCurrVolume = getStreamVolume(); updateVolumePosition(0); mVolumeSb.setProgress(0); } else { //恢复之前音量 updateVolumePosition(mCurrVolume); mVolumeSb.setProgress(mCurrVolume); } } /** * 通过手势改变音量大小 * * @param deltaY */ private void changeGestureVolume(float deltaY) { // 1、触摸(onTouchEvent方法中处理) // 2、识别手势(GuestureDetactor) // 3、计算音量最大值与屏幕高的比例 // 4、计算移动的距离等于多少对应的音量值 //最终的音量=当前音量+滑动距离*比例 int changeVolume = (int) (deltaY * mVolumeScreenHeightScale); int finalVolume = mCurrVolume + changeVolume; // 预防超出范围 if (finalVolume > mMaxVolume) { finalVolume = mMaxVolume; } else if (finalVolume < 0) { finalVolume = 0; } updateVolumePosition(finalVolume); mVolumeSb.setProgress(finalVolume); LogUtils.i(VitamioVideoPlayerActivity.this, "当前音量:" + finalVolume); } /** * 改变亮度 * * @param deltaY */ private void changeGestureBrightness(float deltaY) { // 1、触摸(onTouchEvent方法中处理) // 2、识别手势(GuestureDetactor) // 3、计算亮度最大值与屏幕高的比例 // 4、计算移动的距离等于多少对应的亮度值 float changeBrightness = deltaY * mBrightnessScreenHeightScale; // 5、在原来亮度的基础上加上移动对应的亮度值 //这里取changeBrightness的相反值,是因为往上移动需要屏幕变亮,所以透明度值要变小 float finalBrightness = mCurrBrightness - changeBrightness; if (finalBrightness < 0f) { finalBrightness = 0f; } else if (finalBrightness > 0.8f) { finalBrightness = 0.8f;//这里不能太接近1,1的话就什么都看不到了. } ViewHelper.setAlpha(mBrightnessView, finalBrightness); } /** * 显示系统时间 */ private void updateSysTime() { mHandler.postDelayed(mUpdateSysTimeRunnable, 1000); } /** * 更新视频的播放进度 */ private void updateVideoPosition() { mHandler.postDelayed(mUpdateVideoPositionRunnable, 300); //更新的频率可以调快一点 } /** * 更新视频的二级缓冲 * * @param percent */ private void updateSecondaryProgress(int percent) { int secondaryProgress = (int) (mVideoView.getDuration() * percent / 100f); mVideoSb.setSecondaryProgress(secondaryProgress); } /** * 播放/暂停视频 */ private void play() { if (mVideoView.isPlaying()) { mVideoView.pause(); } else { mVideoView.start(); } setPlayBgSelector(); } /** * 设置播放按钮的背景选择器 */ private void setPlayBgSelector() { //如果当前是播放,则显示暂停背景图片选择器 //如果当前是暂停,则显示播放背景图片选择器 mPlayIb.setImageResource(mVideoView.isPlaying() ? R.drawable.selector_ib_pause : R.drawable.selector_ib_play); } /** * 播放上一个 */ private void pre() { if (mPosition > 0) { mPosition--; setCurrPlayVideo(); } } /** * 播放下一个 */ private void next() { if (mPosition != mVideoList.size() - 1) { mPosition++; setCurrPlayVideo(); } } /** * 在全屏和默认大小之间进行切换 */ private void toggleFullscreen() { mVideoView.toggleFullscreen(); updateFullscreenBtnBg(); } /** * 更新全屏按钮的背景选择器 */ private void updateFullscreenBtnBg() { // 如果当前是全屏的,则显示一个恢复默认大小的按钮 // 如果当前是默认大小的,则显示一个全屏的按钮 mFullScreenIb.setImageResource(mVideoView.isFullscreen() ? R.drawable.selector_ib_default_screen : R.drawable.selector_ib_full_screen); } /** * 隐藏控制面板 */ private void hideControlLayout() { //瞬时执行隐藏动画 // ViewHelper.setTranslationY(mTopControlLl, -mTopControlLl.getMeasuredHeight());//向上移动是负数 // ViewHelper.setTranslationY(mBottomControlLl, mBottomControlLl.getMeasuredHeight());//向下移动是正数 //带动画效果的隐藏控制面板 ViewPropertyAnimator.animate(mTopControlLl).translationY(-mTopControlLl.getHeight()); ViewPropertyAnimator.animate(mBottomControlLl).translationY(mBottomControlLl.getHeight()); } /** * 单击切换控制面板的显示/隐藏 */ private void toggleHideControlLayout() { //获取mTopControlLl当前相对控件Y坐标的位置 float currTranslateY = ViewHelper.getTranslationY(mTopControlLl); if (currTranslateY == 0f) { //当前是显示控制面板的,需要隐藏 hideControlLayout(); } else { //显示控制面板 ViewPropertyAnimator.animate(mTopControlLl).translationY(0f); ViewPropertyAnimator.animate(mBottomControlLl).translationY(0f); //5秒后自动隐藏控制面板 HideControlLayoutDelay(); } } /** * 5秒后自动隐藏控制面板 */ private void HideControlLayoutDelay() { mHandler.removeCallbacks(mHideControlLayoutRunnable); mHandler.postDelayed(mHideControlLayoutRunnable, 5000); } /** * 取消5秒后自动隐藏控制面板,在界面有用户操作(按钮单击、SeekBar手动、Touch事件)的时候取消 */ private void cancelHideControlLayout() { mHandler.removeCallbacks(mHideControlLayoutRunnable); } /** * 更新电量的图标 * * @param level */ private void updateBatteryByLevel(int level) { int resId; if (level == 0) { resId = R.drawable.ic_battery_0; } else if (level <= 10) { resId = R.drawable.ic_battery_10; } else if (level <= 20) { resId = R.drawable.ic_battery_20; } else if (level <= 40) { resId = R.drawable.ic_battery_40; } else if (level <= 60) { resId = R.drawable.ic_battery_60; } else if (level <= 80) { resId = R.drawable.ic_battery_80; } else { resId = R.drawable.ic_battery_100; } mBatteryIv.setImageResource(resId); } @Override public void onClick(View v) { //操作前先取消隐藏控制版面 cancelHideControlLayout(); switch (v.getId()) { case R.id.ib_voice: toggleVolume(); break; case R.id.ib_back: onBackPressed(); break; case R.id.ib_pre: pre(); break; case R.id.ib_play: play(); break; case R.id.ib_next: next(); break; case R.id.ib_fullScreen: toggleFullscreen(); break; } //延迟隐藏控制版面 HideControlLayoutDelay(); } /** * 视频准备完毕的监听 */ MediaPlayer.OnPreparedListener mOnPreparedListener = new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { LogUtils.i(VitamioVideoPlayerActivity.this, ">>>>>>>>>onPrepared"); //隐藏加载圈 mLoadView.setHideProgressBarWidthAlpha(); //开始播放视频 mVideoView.start(); if (null != mVideo) { //显示视频名称 mTitleTv.setText(mVideo.title); } hideControlLayout(); //设置视频进度的最大值 mVideoSb.setMax((int) mVideoView.getDuration()); //设置视频总时长 mVideoDurationTv.setText(TimeUtils.format(mVideoView.getDuration())); //更新播放的进度 updateVideoPosition(); //设置播放按钮的背景选择器 setPlayBgSelector(); } }; /** * 视频播放完毕的监听 */ MediaPlayer.OnCompletionListener mOnCompletionListener = new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { //播放完后,将当前播放进度设置为0 // mHandler.removeCallbacks(mUpdateVideoPositionRunnable); mLoadView.setProgressBarVisiable(false); mCurrVideoPositionTv.setText(TimeUtils.format(0)); mVideoSb.setProgress(0); mVideoView.seekTo(0); mPlayIb.setImageResource(R.drawable.selector_ib_play);//恢复为播放按钮 } }; /** * 电量改变的接收器 */ BroadcastReceiver mBatteryChangeReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // PrintUtils.printIntent(intent); int level = intent.getIntExtra("level", 0);//电量的等级 updateBatteryByLevel(level); } }; /** * 更新系统时间的Runnable */ Runnable mUpdateSysTimeRunnable = new Runnable() { @Override public void run() { mSysTimeTv.setText(DateFormat.format("HH:mm:ss", System.currentTimeMillis())); updateSysTime(); } }; /** * 更新视频播放进度的Runnable */ Runnable mUpdateVideoPositionRunnable = new Runnable() { @Override public void run() { //获取当前进度,是一个时间毫秒值 int currPosition = (int) mVideoView.getCurrentPosition(); //更新时间 mCurrVideoPositionTv.setText(TimeUtils.format(currPosition)); //更新seekBar mVideoSb.setProgress(currPosition); updateVideoPosition(); } }; /** * 定时隐藏控制面板的Runnable */ Runnable mHideControlLayoutRunnable = new Runnable() { @Override public void run() { hideControlLayout(); } }; /** * 音量改变的SeekBar监听器 */ SeekBar.OnSeekBarChangeListener mVolumeSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { //表示是用户拖动改变的 updateVolumePosition(progress); } } //开始拖动 @Override public void onStartTrackingTouch(SeekBar seekBar) { cancelHideControlLayout(); } //停止拖动 @Override public void onStopTrackingTouch(SeekBar seekBar) { HideControlLayoutDelay(); } }; /** * 视频进度改变的SeekBar监听器 */ SeekBar.OnSeekBarChangeListener mVideoSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { //表示是用户拖动改变的 mVideoView.seekTo(progress); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { cancelHideControlLayout(); } @Override public void onStopTrackingTouch(SeekBar seekBar) { HideControlLayoutDelay(); } }; /** * 视频缓冲监听器 */ MediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() { @Override public void onBufferingUpdate(MediaPlayer mp, int percent) { updateSecondaryProgress(percent); } }; /** * 视频卡顿监听器 */ MediaPlayer.OnInfoListener mOnInfoListener = new MediaPlayer.OnInfoListener() { @Override public boolean onInfo(MediaPlayer mp, int what, int extra) { switch (what) { case MediaPlayer.MEDIA_INFO_BUFFERING_START: //开始缓冲 mLoadView.setProgressBarVisiable(true); break; case MediaPlayer.MEDIA_INFO_BUFFERING_END://停止缓冲: mLoadView.setHideProgressBarWidthAlpha(); break; } return true; } }; /** * 手势监听器 */ GestureDetector.SimpleOnGestureListener mOnGestureListener = new GestureDetector.SimpleOnGestureListener() { //长按 @Override public void onLongPress(MotionEvent e) { play(); } //滚动 @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { //获取是指滑动的距离,deltaY>0表示向上滑动,否则表示向下滑动 float deltaY = e1.getY() - e2.getY(); if (mIsLeftDown) { //左侧按下,改变亮度,即mBrightnessView的透明度 changeGestureBrightness(deltaY); } else { //右侧按下,改变音量 changeGestureVolume(deltaY); } return true; } //按下 @Override public boolean onDown(MotionEvent e) { mCurrVolume = getStreamVolume();//获取当前音量 mCurrBrightness = mBrightnessView.getAlpha();//获取当前的亮度view的透明度 mIsLeftDown = e.getX() < UIUtils.getScreenWidth() / 2; //是否在屏幕左侧按下 return super.onDown(e); } //双击 @Override public boolean onDoubleTap(MotionEvent e) { //3种方式执行全屏 //toggleFullscreen(); //onClick(mFullScreenIb); mFullScreenIb.performClick(); // 当过代码的方式去单击这个按钮 return true; } //单击 @Override public boolean onSingleTapConfirmed(MotionEvent e) { //5秒后自动隐藏 toggleHideControlLayout(); return true; } }; @Override public boolean onTouchEvent(MotionEvent event) { //传递触摸事件给手势监听器 mGestureDetector.onTouchEvent(event); switch (event.getAction()) { case MotionEvent.ACTION_UP: HideControlLayoutDelay();//5秒后自动隐藏 break; default: cancelHideControlLayout();//取消自动隐藏 break; } return super.onTouchEvent(event); } @Override protected void onStart() { super.onStart(); //显示系统时间 updateSysTime(); } @Override protected void onStop() { super.onStop(); mHandler.removeCallbacks(mUpdateSysTimeRunnable); } @Override protected void onDestroy() { super.onDestroy(); if (null != mBatteryChangeReceiver) { unregisterReceiver(mBatteryChangeReceiver); } } }
修改布局文件的VideoView全路径
<io.vov.vitamio.widget.VideoView android:id="@id/videoView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true"/>
修改清单文件中播放器的类名
android:name=".module.video.VitamioVideoPlayerActivity"
当然上述的所有操作都是在关联了vitamio库之后的.
最后还需要在Vitamio库的VideoView源码上增加个全屏和按比例播放直接的切换.直接加在源码最后面即可:
/** * 全屏和按比例播放间的切换 */ public void toggleFullscreen() { int layout; if (mVideoLayout == VIDEO_LAYOUT_STRETCH) { //当前是全屏播放,调用后设置为按比例播放 layout = VIDEO_LAYOUT_SCALE; } else { //当前是按比例播放,调用后设置为全屏播放 layout = VIDEO_LAYOUT_STRETCH; } float aspectRatio = 0; setVideoLayout(layout, aspectRatio); } /** * 当前的播放模式是否是全屏播放 */ public boolean isFullscreen() { return mVideoLayout == VIDEO_LAYOUT_STRETCH; }