<VideoView
android:id="@+id/sys_video"
android:layout_width="match_parent"
android:layout_height="280dp"/>
//在读取本地文件之前一定要注意是否具有读取文件的权限。
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()
根据页面设计要求编写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>
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.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.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.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
private var fullScreen = false
full_screen.setOnClickListener{
//全屏-->半屏
if(fullScreen){
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}
//半屏-->全屏
else{
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
}
}
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)
获取滑动事件
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