Android学习过程之自定义video

裴嘉许
2023-12-01


一、使用系统自带的VideoView播放视频

  1. 在资源文件中添加VideoView标签
<VideoView
	android:id="@+id/sys_video"
	android:layout_width="match_parent"
	android:layout_height="280dp"/>
  1. 在Activity类中调用
//在读取本地文件之前一定要注意是否具有读取文件的权限。

val path = Environment.getExternalStorageDirectory().absolutePath+"/hello.mp4"

val controller = MediaController(this)
sys_video.setMediaController(controller)
//访问本地视频
sys_video.setVideoPath(path)

//访问网络视频
sys_video.setVideoURI(Uri.parse(path))

sys_video.start()

注意: 当视频无法播放时,一般可能为无法打开此视频文件,此时需注意软件是否含有读取文件的权限。在读取文件之前要确保软件已经获取了文件的访问权限。

二、自定义播放器

1. 新建播放器样式文件

根据页面设计要求编写video显示页面的样式文件。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutDescription="@xml/activity_main_scene"
    tools:context=".MainActivity">


    <RelativeLayout
    
		android:id="@+id/layout_view"
        android:layout_width="match_parent"
        android:layout_height="300dp">

        <VideoView
            android:id="@+id/sys_video"
            android:layout_width="match_parent"
            android:layout_height="250dp" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_alignParentBottom="true"
            android:orientation="vertical">

            <SeekBar
                android:id="@+id/progress_bar"
                android:layout_width="match_parent"
                android:layout_height="5dp"
                android:thumb="@null" />

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="#101010"
                android:gravity="center_vertical">

                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:gravity="center_vertical"
                    android:orientation="horizontal">

                    <ImageButton
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="10dp" />

                    <TextView
                        android:id="@+id/time_remain"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="10dp"
                        android:text="00:00:00"
                        android:textColor="#ffffff"
                        android:textSize="25dp" />

                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="5dp"
                        android:text="/"
                        android:textColor="#4c4c4c"
                        android:textSize="25dp" />

                    <TextView
                        android:id="@+id/time_total"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="5dp"
                        android:text="00:00:00"
                        android:textColor="#4c4c4c"
                        android:textSize="25dp" />


                </LinearLayout>

                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:gravity="center_vertical"
                    android:layout_alignParentRight="true"
                    android:orientation="horizontal">

                    <View
                        android:layout_width="1dp"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="5dp"
                        android:layout_marginBottom="5dp" />

                    <ImageView
                    	android:id="@+id/voice_icon"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:src="@drawable/voice_icon"               
                        android:visibility="gone" />

                    <SeekBar
                        android:id="@+id/voice"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:thumb="@null"
                        android:visibility="gone" />

                    <ImageButton
                        android:id="@+id/full_screen"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:src="@drawable/full_screen_icon"
                         />

                </LinearLayout>

            </RelativeLayout>

        </LinearLayout>

    </RelativeLayout>
    
</RelativeLayout>

2. 添加响应函数

fun videoOrButtonClick(){
	if(sys_video.isPlaying){
		start_pause.setImageResource(R.drawable.pause_image)
		sys_video.pause()
		myHandler.removeMessage(MSG_UPDATE)
	}else{
		start_pause.setImageResource(R.drawable.start_image)
		sys_video.start()
		myHandler.sendEmptyMessage(MSG_UPDATE)

	}
}

 fun setClickEvent(){
	//添加按键响应函数
	start_pause.setOnclickListener(){
		 videoOrButtonClick()
	}
	//添加屏幕单击事件响应函数
	sys_video.setOnclickListener(){
		 videoOrButtonClick()
	}
	
	
//添加进度条拖动响应函数。
	progress_bar.setOnSeekBarChangeListener(object:OnSeekBarChangeListener{
		override fun onProgressChanged(seekBar:SeekBar?, progress:Int, fromUser:Boolean){
			time_remain.text = positionToTime(progress)
		}
		override fun onStartTrackingTouch(seekBar:SeekBar?){
			myHandler.removeMessage(MSG_UPDATE)
		}
	
		override fun onStopTrackingTouch(seekBar:SeekBar?){
			sys_video.seekTo(seekBar!!.progress)
			myHandler.sendEmptyMessage(MSG_UPDATE)
		}
	})
}

3.实现页面数据填充

3.1 实现页面数据定时刷新

	//在MainActivity 中创建内部类,MyHandler, 创建消息常量MSG_UPDATE
	val MSG_UPDATE = 1
	inner class MyHandler:Handler(){
	override fun handleMessage(message:Message){
		if(message.what == MSG_UPDATE){
		//positionToTimeString  函数返回Int值对应的时间格式
			time_total.text = positionToTimeString(sys_video.duration)
			time_remain.text = positionToTime(sys_video.currentPosition)

			progress_bar.max = sys_video.duration
			progress_bar.progress = sys_video.currentPosition
			sendEmptyMessageDelayed(MSG_UPDATE, 500)
		}
	}
}

4.实现横竖屏切换

4.1 横竖屏切换时视频会从新开始播放,此时需要在AndroidManifest.xml中添加confgChanges

<!-- 在activity 中添加configChanges属性 -->
<activity
android:configChanges="screenSize|keyboard|orientation|keyboardHidden
android:name=".MainActivity"
>"

4.2 设置横竖屏屏幕大小

说明:此时视频可切换成横屏状态,但是视频大小无法拉伸,若需要视频可自适应屏幕大小,则需自定义VideoView

//自定义设置窗口大小函数
fun setVideoViewScale(width:Int, height:Int){
	sys_video.layoutParams.width = width
	sys_video.layoutParams.heigth = height
	layout_view.layoutParams.width = width
	layout_view.layoutParams.heigth = height
}
//sp转换成dp
val Int.dp: Int
        get() = android.util.TypedValue.applyDimension(
            android.util.TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics).toInt()
            
//重写onConfigurationChanged函数
override fun onConfigurationChanged(newConfig:Configuration){
	super.onConfigurationChanged(newConfig)
	//判断是不是横向
	if(resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE){
		setVideoViewScale(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT)
	}
	else{
	//屏幕的具体值需进行转换。		
		setVideoViewScale(ViewGroup.LayoutParams.MATCH_PARENT, 250.dp)
	}
}

5. 添加音量设置

5.1 获得audioService

	private lateinit var audioService:AudioManager

在Activity的OnCreate中获得服务。并设置最大音量和当前音量

切记:在OnCreate 之前是无法获得服务的

	audioService = getSystemService(AUDIO_SERVICE) as AudioManager
	voice.max = audioService.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
	voice.progress = audioService.getStreamVolume(AudioManager.STREAM_MUSIC)

5.2 添加voice seekBar的监听函数

voice.setOnSeekBarChangeListener(object:OnSeekBarChangeListener{
	
	override fun onProgressChanged(seekBar:SeekBar?, progress:Int, fromUser:Boolean){
		audioService.setStreamVolume(AudioManager.STREAM_MUSIC, progress, 0)
	}
	override fun onStartTrackingTouch(seekBar:SeekBar?){
	}
	override fun onStopTrackingTouch(seekBar:SeekBar?){}
})

5.3 设置横屏时voice 进度条可见

在sys_video的监听函数中添加:横屏时设置voice 进度条可见,竖屏时隐藏。
	//横屏时:
	voice.visibility = VISIBLE
	voice_icon.visibility = VISIBLE

	//竖屏时:
	voice.visibility = GONE
	voice_icon.visibility = GONE

6. 按键切换全屏和半屏

	private var fullScreen = false
	full_screen.setOnClickListener{
	//全屏-->半屏
	if(fullScreen){
		requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
	}
	//半屏-->全屏
	else{
		requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
	}
}

7. 设置适应全屏

7.1 自定义VideoView继承自VideoView

class MyVideoView(context:Context, attrs:AttributeSet?):VideoView(context,attrs){
	val default_Width = 1920
	val default_Height = 1080
	override fun onMeasure(widthMeasureSpec:Int,heightMeasureSpec:Int){
		super.onMesure(widthMeasureSpec, heightMeasureSpec)
		var width = getDefaultSize(default_Width, widthMeasureSpec)
		var height = getDefaultSize(default_Height, heightMeasureSpec)

		setMeasureDimension(width, height)
	}
}

7.2 更改xml文件中的组件类型

将样式文件中的 <VideoView 标签改为:<com.example.myvideo.MyVideoView 

7.3 更新横竖屏监听函数

//在sys_video.setOnConfigurationChanged 修改标志位

//横屏时:
	window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN)
	window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)


//竖屏时:
	window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
	window.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN)

8. 滑动屏幕调节音量和亮度

获取滑动事件

 sys_video.setOnTouchListener(v,event->
 	var X = event!!.getX()
 	var Y = event!!.getY()
 	
	when(event!!.action){
		//手指按下触发
		MotionEvent.ACTION_DOWN->{

		}
		//手指移动时触发, 多次调用
		MotionEvent.ACTION_MOVE->{}
		//手指离开时触发
		MotionEvent.ACTION_UP->{}
	}
	true
)

根据初始位置判断更改亮度还是声音。

调节屏幕亮度:

  window.attributes.screenBrightness += detlaBright
 类似资料: