Creo que aquellos que hacen desarrollo de Android generalmente han reproducido videos web. Todos generalmente usan VideoView para reproducir videos web, y también hay un controlador para controlar la pausa o el avance rápido del video. Pero el estilo de Controller no se puede cambiar para que sea particularmente feo. No puedo cumplir con la experiencia de IU de gama alta.
Complete un controlador de reproducción personalizado y una sencilla función de cambio de pantalla horizontal y vertical. Probablemente registre el proceso:
1. Personalice MyVideoView para resolver el problema que puede no cubrir toda la pantalla y causar bordes en blanco.
public class MyVideoView extends VideoView {
public MyVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = getDefaultSize(0,widthMeasureSpec);
int height = getDefaultSize(0,heightMeasureSpec);
setMeasuredDimension(width,height);
}
}
2. Coloque VideoView y Controller en un archivo xml en un diseño.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/rl_content"
android:layout_width="match_parent"
android:layout_height="200dp">
<!-- 播放视频的VideoView -->
<com.teach.myapplication.MyVideoView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- 控制器 -->
<RelativeLayout
android:id="@+id/rl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<!-- 自定义样式后的SeekBar进度条 -->
<SeekBar
android:id="@+id/sb"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/ll"
android:maxHeight="4dp"
android:minHeight="4dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:progressDrawable="@drawable/seekbar_shape"
android:thumb="@mipmap/icon_seekbar_button"
android:thumbOffset="20dp" />
<LinearLayout
android:paddingBottom="3dp"
android:id="@+id/ll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="16dp"
android:orientation="horizontal">
<!-- 当前播放位置 -->
<TextView
android:id="@+id/tv_process_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00"
android:textColor="#0E83F8"
android:textSize="13sp" />
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="/"
android:textColor="#FFFFFF"
android:textSize="13sp" />
<!-- 视频总时长 -->
<TextView
android:id="@+id/tv_all_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00"
android:textColor="#FFFFFF"
android:textSize="13sp" />
</LinearLayout>
<!-- 全屏按钮 -->
<ImageView
android:paddingBottom="3dp"
android:id="@+id/iv_full_screen"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="16dp"
android:src="@mipmap/icon_quanping" />
<!-- 播放暂停按钮 -->
<ImageView
android:id="@+id/iv_play_or_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/sb"
android:layout_centerHorizontal="true"
android:src="@mipmap/icon_dianbo_play" />
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
3. MediaView personalizado
/**
* 自定义的视频播放器
*/
public class MediaView extends FrameLayout implements SeekBar.OnSeekBarChangeListener, View.OnClickListener, MediaPlayer.OnPreparedListener, View.OnTouchListener {
/**
* 视频播放VideoView
*/
private MyVideoView videoView;
/**
* 进度SeekBar
*/
private SeekBar sb;
/**
* 播放总时长 和当前播放时长
*/
private TextView tv_process_date, tv_all_date;
/**
* 全屏播放按钮
*/
private ImageView iv_full_screen;
/**
* 播放或者暂停按钮
*/
private ImageView iv_play_or_pause;
/**
* 播放控制器
*/
private RelativeLayout rl, rl_content;
/**
* 是否正在播放视频
*/
private boolean playing;
/**
* 当前播放至的进度
*/
private int progress;
/**
* 时间定时器
*/
private Timer timer;
private TimerTask task;
private Handler handler;
/**
* 是否展示控制器
*/
private boolean showIng;
private Context context;
private boolean isFullScreen;
private int mHeight;
public MediaView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
this.context = context;
View view = LayoutInflater.from(context).inflate(R.layout.my_mediacontroller_layout, this, true);
videoView = view.findViewById(R.id.videoView);
sb = view.findViewById(R.id.sb);
sb.setOnSeekBarChangeListener(this);
tv_process_date = view.findViewById(R.id.tv_process_date);
tv_all_date = view.findViewById(R.id.tv_all_date);
iv_full_screen = view.findViewById(R.id.iv_full_screen);
iv_full_screen.setOnClickListener(this);
iv_play_or_pause = view.findViewById(R.id.iv_play_or_pause);
iv_play_or_pause.setOnClickListener(this);
rl = view.findViewById(R.id.rl);
rl_content = view.findViewById(R.id.rl_content);
videoView.setOnTouchListener(this);
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1) {
//do something
sb.setProgress(videoView.getCurrentPosition());
tv_process_date.setText(DateFormatUtils.getDateFormat(videoView.getCurrentPosition()));
} else if (msg.what == 2) {
rl.setVisibility(View.GONE);
showIng = false;
}
super.handleMessage(msg);
}
};
}
/**
* 播放器准备
*
* @param url
*/
public void start(String url) {
videoView.setVideoPath(url);
videoView.setOnPreparedListener(this);
}
/**
* 播放
*/
public void play() {
videoView.seekTo(videoView.getCurrentPosition());
playing = true;
videoView.start();
Log.e("lee", "播放的时候" + DateFormatUtils.getDateFormat(videoView.getCurrentPosition()));
Log.e("lee", "播放的时候" + videoView.getCurrentPosition());
timer = new Timer();
task = new TimerTask() {
@Override
public void run() {
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
}
};
timer.schedule(task, 0, 1000);
handler.postDelayed(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.what = 2;
handler.sendMessage(message);
}
}, 5000);
iv_play_or_pause.setImageResource(R.mipmap.icon_dianbo_pause);
}
/**
* 暂停
*/
public void pause() {
videoView.pause();
Log.e("lee", "暂停的时候" + DateFormatUtils.getDateFormat(videoView.getCurrentPosition()));
Log.e("lee", "暂停的时候" + videoView.getCurrentPosition());
timer.cancel();
}
/**
* seekbar监听器
*/
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
tv_process_date.setText(DateFormatUtils.getDateFormat(progress));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
videoView.pause();
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
videoView.seekTo(seekBar.getProgress());
videoView.start();
playing = true;
iv_play_or_pause.setImageResource(R.mipmap.icon_dianbo_pause);
}
/**
* 点击事件
*
* @param v
*/
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.iv_play_or_pause://播放暂停按钮
if (playing) {//正在播放 (点击暂停)
iv_play_or_pause.setImageResource(R.mipmap.icon_dianbo_play);
pause();
playing = false;
} else {//正在暂停 (点击播放)
iv_play_or_pause.setImageResource(R.mipmap.icon_dianbo_pause);
play();
playing = true;
}
break;
case R.id.iv_full_screen:
if (!isFullScreen) {//竖屏状态(切换成横屏)
//首先获得原来的高度
mHeight = rl_content.getHeight();
//重新制定高度
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) rl_content.getLayoutParams();
params.height = ViewGroup.LayoutParams.MATCH_PARENT;
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
((MainActivity) context).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);//显示顶部状态栏
((MainActivity) context).getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
((MainActivity) context).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
rl_content.setLayoutParams(params);
isFullScreen = true;
} else {//横屏状态(切换成竖屏)
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) rl_content.getLayoutParams();
params.height = mHeight;
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
((MainActivity) context).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//全屏不 显示顶部状态栏
((MainActivity) context).getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
((MainActivity) context).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
rl_content.setLayoutParams(params);
isFullScreen = false;
}
break;
default:
break;
}
}
/**
* 视频加载成功
*
* @param mp
*/
@Override
public void onPrepared(MediaPlayer mp) {
sb.setMax(videoView.getDuration());
tv_process_date.setText(DateFormatUtils.getDateFormat(videoView.getCurrentPosition()));
tv_all_date.setText(DateFormatUtils.getDateFormat(videoView.getDuration()));
//播放
play();
/**
* 视频播放完成监听
*/
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
videoView.seekTo(0);
sb.setProgress(0);
playing = false;
rl.setVisibility(View.VISIBLE);
showIng = true;
iv_play_or_pause.setImageResource(R.mipmap.icon_dianbo_play);
}
});
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.e("lee", "ACTION_DOWN");
rl.setVisibility(View.VISIBLE);
showIng = true;
if (showIng) {
handler.removeMessages(2);
}
break;
case MotionEvent.ACTION_MOVE:
Log.e("lee", "ACTION_MOVE");
if (showIng) {
handler.removeMessages(2);
}
break;
case MotionEvent.ACTION_UP:
Log.e("lee", "ACTION_DOWN");
handler.postDelayed(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.what = 2;
handler.sendMessage(message);
}
}, 5000);
break;
default:
break;
}
return true;
}
}
4. Llamada externa
Código en actividad
mediaView = findViewById(R.id.view);
mediaView.start("http://vfx.mtime.cn/Video/2019/06/26/mp4/190626111517361726.mp4");
código xml
<com.teach.myapplication.MediaView
android:id="@+id/view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Tenga en cuenta que la actividad debe agregarse en el archivo de manifiesto
android:screenOrientation="portrait"
android:configChanges="orientation|screenSize|keyboardHidden"
5. El estilo de seekbar seekbar_shape.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<corners android:radius="2dp" />
<solid android:color="#33FFFFFF" />
</shape>
</item>
<item android:id="@android:id/secondaryProgress">
<clip>
<shape>
<corners android:radius="2dp" />
<solid android:color="#77FFFFFF" />
</shape>
</clip>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="2dp" />
<solid android:color="#0E83F8" />
</shape>
</clip>
</item>
</layer-list>
Lo anterior ha completado el controlador de reproducción personalizado simple y simplemente puede cambiar la función de reproducción entre pantallas horizontales y verticales, y los íconos de pausa y reproducción no se cargarán, solo reemplácelos con su propio nombre.