一、实现效果
废话不多说,直接上代码,里面有详细注释,不清楚的评论区留言。
二、布局代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:background="@color/background"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<ImageButton
android:id="@+id/video_file"
android:layout_width="12dp"
android:layout_height="12dp"
android:background="@mipmap/video_file"/>
<TextView
android:id="@+id/open_video"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:clickable="true"
android:textSize="8dp"
android:text="本地视频"/>
</LinearLayout>
<VideoView
android:id="@+id/video"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<LinearLayout
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_marginLeft="3dp"
android:layout_alignParentBottom="true"
android:gravity="center_vertical"
android:layout_height="wrap_content">
<TextView
android:id="@+id/play_video"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:clickable="true"
android:text="播放"
android:textColor="@color/white"
android:layout_weight="2"
android:textSize="10dp"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text=" | "/>
<TextView
android:id="@+id/pause_video"
android:layout_width="0dp"
android:clickable="true"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="暂停"
android:textColor="@color/white"
android:textSize="10dp"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text=" | "/>
<TextView
android:id="@+id/replay_video"
android:layout_width="0dp"
android:clickable="true"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="重播"
android:textColor="@color/white"
android:textSize="10dp"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text=" | "/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/seekbar_start_second"
android:text="0"
android:textSize="8dp"
android:layout_weight="1"
android:textColor="@color/white"/>
<SeekBar
android:layout_width="0dp"
android:id="@+id/seekbar_video"
android:layout_height="wrap_content"
android:layout_weight="60"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/seekbar_max_second"
android:text="0"
android:textSize="8dp"
android:layout_weight="1"
android:textColor="@color/white"/>
</LinearLayout>
</RelativeLayout>
三、Activity代码
package com.example.tabtest.activity;
import android.app.Activity;;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.VideoView;
import com.example.tabtest.R;
import com.example.tabtest.util.FormatTime;
/**
* author lishilin
* date 2023-7-25
* 描述 视频播放器,自定义播放进度条,可以打开文件管理器选择本地视频进行播放
*/
public class VideoActivity extends Activity implements View.OnClickListener {
private VideoView video;
private TextView startPlay;
private TextView pausePlay;
private int totalSeconds;//视频总时长,单位,毫秒
private int currentSeconds;//当前视频进度
private int seekBarMax;//进度条最大值
private SeekBar seekBar;//进度条
private TextView seekBarMaxSecond;//进度条最大秒数
private TextView seekBarStartSecond;//进度条开始秒数
private FormatTime formatTime;
private TextView replay;
private TextView openVideo;
private ImageButton videoFile;
@Override
public void onCreate(Bundle saveInstanceState){
super.onCreate(saveInstanceState);
setContentView(R.layout.video_play);
initView();
formatTime = new FormatTime();
updateSeekbar();//监听进度条滑块
playListener();//设置视频加载监听器
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//强制页面横屏
}
/**
* 点击事件
* @param view
*/
@Override
public void onClick(View view){
switch (view.getId()){
case R.id.play_video:
if (!video.isPlaying()){
video.start();
}
break;
case R.id.pause_video:
if (video.isPlaying()){
video.pause();
}
break;
case R.id.replay_video:
video.resume();
break;
case R.id.open_video:
case R.id.video_file:
toOpenVideo();
break;
default:
break;
}
}
/**
* 初始化组件
*/
private void initView(){
video = (VideoView) findViewById(R.id.video);
String videoPath = "https://vfx.mtime.cn/Video/2019/07/12/mp4/190712140656051701.mp4";//网络视频地址
video.setVideoPath(videoPath);
// Uri uri = Uri.parse("android.resource://"+getPackageName()+"/"+R.raw.test); //本地视频地址
// video.setVideoURI(uri);//设置视频播放路径
video.requestFocus();//视频获取焦点
seekBar = (SeekBar) findViewById(R.id.seekbar_video);
seekBarMaxSecond = (TextView) findViewById(R.id.seekbar_max_second);
seekBarStartSecond = (TextView) findViewById(R.id.seekbar_start_second);
replay = (TextView) findViewById(R.id.replay_video);
replay.setOnClickListener(this);
startPlay = (TextView) findViewById(R.id.play_video);
pausePlay = (TextView) findViewById(R.id.pause_video);
openVideo = (TextView) findViewById(R.id.open_video);
videoFile = (ImageButton) findViewById(R.id.video_file);
videoFile.setOnClickListener(this);
openVideo.setOnClickListener(this);
startPlay.setOnClickListener(this);
pausePlay.setOnClickListener(this);
}
/**
* 设置视频播放时候的动作监听,并作出相应的处理,比如进度条更新等操作
*/
private void playListener(){
//监听视频准备加载完毕之后执行
video.setOnPreparedListener(mediaPlayer -> {
video.start();
totalSeconds = video.getDuration();//获取视频总毫秒数
seekBarMaxSecond.setText(formatTime.SecondToTime(totalSeconds/1000));//设置进度条最大时间秒数
seekBarMax = totalSeconds;
seekBar.setMax(seekBarMax);
//异步更新ui,利用消息机制处理子线程的需求
Handler mhandler = new Handler(){
@Override
public void handleMessage(Message message){
if(message.what == 1){
updateProcess();//更新视频播放时间和进度条
}
}
};
//子线程里执行循环发送消息
new Thread(new Runnable() {
@Override
public void run() {
currentSeconds = video.getCurrentPosition();//获取视频播放进度,返回值为毫秒
while (true){
Message message = new Message();
message.what = 1;
mhandler.sendMessage(message);
try {
Thread.sleep(1);//设置一毫秒更新一次进度条ui,这里可以改成想要的值
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
});
}
/**
* 更新视频播放时间和进度条
*/
private void updateProcess(){
currentSeconds = video.getCurrentPosition();
seekBarStartSecond.setText(formatTime.SecondToTime(currentSeconds/1000));
seekBar.setProgress(currentSeconds);
}
/**
* 监听进度条滑块
*/
public void updateSeekbar(){
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
//停止滑动的时候执行下面的方法
@Override
public void onStopTrackingTouch(SeekBar seekBar1) {
int current = seekBar.getProgress();
video.seekTo(current);
seekBarStartSecond.setText(formatTime.SecondToTime(currentSeconds/1000));
}
});
}
/**
* 打开视频文件并播放
*/
private void toOpenVideo(){
video.pause();
Intent intent=new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");//设置类型,这是任意类型
intent.addCategory(Intent.CATEGORY_OPENABLE);
//打开一个activity,并在onActivityResult方法里面接收回调数据,更新视频地址
startActivityForResult(intent,1);
//销毁上一个视频
video.suspend();
}
private static final int FILE_SELECT_CODE = 1;
/**
* 处理打开文件之后的行为,如给video设置视频路径,该方法是activity在执行完startActivityForResult(intent,1)方法之后自动执行的,无需调用;
* @param requestCode
* @param resultCode
* @param data
*/
public void onActivityResult(int requestCode,int resultCode,Intent data){
if(resultCode == Activity.RESULT_OK){
Uri uri = data.getData();
video.setVideoURI(uri);
video.requestFocus();
super.onActivityResult(requestCode,resultCode,data);
return;
}
if (resultCode == FILE_SELECT_CODE){
Uri uri = data.getData();
Log.d("videoActivity",uri.getPath());
}
super.onActivityResult(requestCode,resultCode,data);
}
@Override
public void onDestroy() {
video.suspend();
Log.i("视频播放器","释放资源");
super.onDestroy();
}
}
自定义一个进度条时间转换工具类,超简单
public class FormatTime {
public String SecondToTime(int seconds){
int second = seconds % 60;
int m = seconds / 60;
int h = seconds /60 /60;
return h+":"+m+":"+second;
}
}