前言
不知道还有多少小伙伴在用系统的VideoView用来播放视频,应该一直有一个问题困扰的大家吧,那就是播放前的一小段黑屏问题。无论是首次播放黑屏还是视频切换黑屏,一个看似小小的问题,却非常难以解决。最近我们app需要播放一些简单的教程视频,不值得引入三方库增大包体积,所以就用了VideoView,黑屏问题就来了。本篇旨在彻底解决黑屏的问题。
单个视频播放前的黑屏
这个问题很好解决,网上也有一堆的教程。不过最近在我测试的过程中发现这些教程有时候并不能解决问题。所以我带来我解决问题的方式。
首先需要给
VideoView
一个单独的
ImageView
设置背景,并且这个
ImageView
的绘制级别一定要高于
VideoView
,保证
VideoView
和
ImageView
都显示的情况下,能让
ImageView
盖住
VIdeoView
。
比如说,我们用自定义一个布局:
<?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">
<VideoView
android:id="@+id/simple_video_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_margin="1px"
android:layout_alignParentTop="true" />
<ImageView
android:id="@+id/simple_video_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:background="@color/app_background" />
</RelativeLayout>
此时ImageView肯定会盖住VideoView,显示一个背景色。
然后需要在代码中设置以下:
private fun initVideoView() {
binding.simpleVideoView.setOnPreparedListener {
it.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING)
binding.simpleVideoView.setOnInfoListener { _, what, _ ->
if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
binding.simpleVideoBg.visibility = GONE
binding.simpleVideoView.start()
这个大家看过其他教程的情况下都理解是什么意思,唯一不同的区别在于用我们在xml中配置的ImageView来替代设置VideoView的背景。
同时给ImageView渲染下视频的第一帧,可以用Glide来实现。Glide可以加载视频资源到ImageView上,就是加载的第一帧。
这样视频播放的情况下就比较完美了,视频渲染完成前会展示视频第一帧,渲染完成后,背景ImageView会隐藏,显示出被盖住的VideoView,避开了VIdeoView渲染视频时的黑色背景。
视频来回切换导致黑屏
如果是在一个VideoView切换不同的视频源,并不会导致黑屏。出现黑屏的情况在于使用多个VideoView来回切换的情况下,比如ViewPager左右切换,首次播放的情况下,用我们上边的办法是可以解决黑屏问题,但来回切换就会发现黑屏又出现了。
问题在于切换的后VideoView会被销毁回收,下次切换回来重新渲染视频。而我们的背景ImageView已经隐藏掉了。
解决问题的关键就在于切换走的VideoView要将背景色ImageView重新显示出来就ok了。
不过不能在setOnPreparedListener中设置ImageView的显示,不会有任何效果,这种问题要结合自己使用的控件来灵活处理。比如我们使用了ViewPager2,那就这样处理:
private var oldPosition = 0
fun initValue() {
binding.commonNoviceCourseViewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
if (oldPosition == position) return
val video = adapter.getViewByPosition(oldPosition, R.id.common_novice_course_video) as SimpleVideoView
video.getVideoBg().visibility = View.VISIBLE
oldPosition = position