Android进阶——巧借自定义VideoView实现Activity的动态视频背景
引言
话说这个Activity 动态背景我第一次是在一个**App上看到的,当时感觉逼格很高,最近正好用到项目中,而且好像好久没有写关于UI这些“有趣”的文章啦,这篇文章就简单小结下,其实实现动态背景这并不是唯一的方案,还有其他的方式。
一、VideoView
1、VideoView概述
VideoView继承自SurfaceView 并实现了MediaController.MediaPlayerControl接口, 是一种可以直接加载并播放来自多种路径(比如 resources 、raw、 content providers)的视频文件资源的官方控件,可以像其他任何普通控件一样在任意布局中声明并使用,有了他使得一些简单播放视频的工作变得简单(但是不适合应用在大型复杂项目等专业的播放音视频的项目中)。需要注意的是VideoView不会自动保存播放状态和播放位置等,所以当进入到后台前,若需要再再次返回时恢复 所选曲目或通过addSubtitleSource()添加的任何字幕轨道等状态, 应在Activity.onSaveInstanceState(Bundle)和Activity.onRestoreInstanceState(Bundle)中自行保存和恢复这些内容。
2、VideoView 重要的成员方法
名称 | 说明 |
---|---|
void addSubtitleSource(InputStream is, MediaFormat format) | 添加外部字幕文件流 |
boolean isPlaying() | 判断是否正在播放 |
int getCurrentPosition() | 获取当前播放位置 |
void seekTo(int msec) | 跳转到指定位置 |
void setOnCompletionListener(MediaPlayer.OnCompletionListener l) | 设置一个在媒体文件加载并准备就绪时调用的回调。 |
void setOnCompletionListener(MediaPlayer.OnCompletionListener l) | 设置一个在媒体文件播放完毕,到达终点时调用的回调 |
void setOnErrorListener(MediaPlayer.OnErrorListener l) | 设置一个在媒体文件播放或者设置时发生错误调用的回调 |
void setVideoPath(String path) | 设置播放视频的字符串路径 |
void setVideoURI(Uri uri, Map<String, String> headers) | 使用指定的头部设置播放视频的URi |
void setVideoURI(Uri uri) | 设置视频的URi |
void setMediaController(MediaController controller) | 设置视频播放控制器 |
二、自定义VideoView实现动态视频背景
其实原理很简单就是利用VideoView控件播放指定的一个视频文件,并把之设置为全屏幕的(非必须要求结合自己的需求来定),然后在生命周期方法中利用提供的各种方法进行监听。
1、 继承VedioView 重写onMeasure方法,为了更好的自适应全屏幕
package com.crazymo.activitybganim.widget;
import android.content.Context;
import android.media.MediaPlayer;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.widget.VideoView;
/**
* Auther: Crazy.Mo on 2018/8/24 14:35
* Summary:继承VideoView实现自适应全屏幕
*/
public class CustomVideoView extends VideoView {
public CustomVideoView(Context context) {
this(context,null);
}
public CustomVideoView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public CustomVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//重新计算高度
int width = getDefaultSize(0, widthMeasureSpec);
int height = getDefaultSize(0, heightMeasureSpec);
setMeasuredDimension(width, height);
}
/**
* @param pPreparedListener 设置一个在媒体文件加载并准备就绪时调用的回调。
*/
@Override
public void setOnPreparedListener(MediaPlayer.OnPreparedListener pPreparedListener) {
super.setOnPreparedListener(pPreparedListener);
}
/**
* @param pCompletionListener 设置一个在媒体文件播放完毕,到达终点时调用的回调。
*/
@Override
public void setOnCompletionListener(MediaPlayer.OnCompletionListener pCompletionListener) {
super.setOnCompletionListener(pCompletionListener);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return super.onKeyDown(keyCode, event);
}
}
- 在布局文件中声明自定义的VedioView
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.crazymo.activitybganim.widget.CustomVideoView
android:id="@+id/videoview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher_round"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="60sp"
android:textColor="#f00"
android:text="视频背景上的TextView"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="60sp"
android:textColor="#00f000"
android:hint="视频背景上的EditText"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button Click"
android:onClick="test"/>
</LinearLayout>
</FrameLayout>
- 在Activity中初始化VideoView并在对应的周期方法中进行对应的监听处理
package com.crazymo.activitybganim;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;
import com.crazymo.activitybganim.widget.CustomVideoView;
public class MainActivity extends AppCompatActivity {
//创建播放视频的控件对象
private CustomVideoView mVideoView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setFullScreen();
setContentView(R.layout.activity_main);
initView();
}
private void setFullScreen() {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
@Override
protected void onRestart() {
//返回时重新加载视频,防止退出或返回时视频黑屏
initView();
super.onRestart();
}
@Override
protected void onPause() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mVideoView.stopNestedScroll();
}
super.onPause();
}
//防止锁屏或者切出的时候,音乐在播放
@Override
protected void onStop() {
if(mVideoView !=null) {
mVideoView.stopPlayback();
}
super.onStop();
}
private void initView() {
mVideoView = findViewById(R.id.videoview);
//设置将要播放视频文件的加载路径仅支持 3gp、MP4、avi
mVideoView.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" +R.raw.bg));//此处播放/res/raw下,也可以播放其他路径的调用对应的方法设置即可
mVideoView.requestFocus();
mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
if (mp.isPlaying()) {
mp.stop();
mp.release();
mp = new MediaPlayer();
}
mp.setVolume(0f, 0f);//设置0,0为静音时
mp.setLooping(true);
mp.start();
}
});
mVideoView.setFocusable(false);
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
mVideoView.start();
}
});
}
public void test(View view) {
Toast.makeText(this,"在背景视频上点击按钮",Toast.LENGTH_SHORT).show();
}
}