1. 配置信息
1.1 AndroidManifest.xml 添加网络权限
<uses-permission android:name="android.permission.INTERNET" />
1.2 使用 Http 明文设置
android:usesCleartextTraffic="true"
1.3 使用竖屏设置
android:screenOrientation="portrait"
1.4 使用协程引用库
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.0-alpha03'
1.5 themes.xml 文件设置无操作栏, 全屏
Theme.MaterialComponents.DayNight.NoActionBar
<item name="android:windowFullscreen">true</item>
1.6 功能说明
使用ViewPager2的嵌套实现左右、上下滑动的列表视频播放
2. 实现 Fool 页面
2.1 布局文件 fragment_foo.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".FooFragment">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/hello_blank_fragment"
android:textSize="24sp" />
</FrameLayout>
2.2 调用布局 FooFragment.kt
class FooFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_foo, container, false)
}
}
3. Player 视频播放View
3.1 布局文件 fragment_player.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".PlayerFragment">
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<ProgressBar
android:id="@+id/progressBarHor"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" />
</FrameLayout>
3.2 实现播放器 PlayerFragment.kt
class PlayerFragment(private val url:String) : Fragment() {
private var mediaPlayer = MediaPlayer()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_player, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val progressBar: ProgressBar = view.findViewById(R.id.progressBar)
val progressBarHor: ProgressBar = view.findViewById(R.id.progressBarHor)
val surfaceView: SurfaceView = view.findViewById(R.id.surfaceView)
mediaPlayer.apply {
setOnPreparedListener {
progressBarHor.max = mediaPlayer.duration
//it.start();
seekTo(1)
progressBar.visibility = View.INVISIBLE
}
setDataSource(url)
prepareAsync()
progressBar.visibility = View.VISIBLE
}
//kut
lifecycleScope.launch {
while (true){
progressBarHor.progress = mediaPlayer.currentPosition
delay(500)
}
}
surfaceView.holder.addCallback(object : SurfaceHolder.Callback{
override fun surfaceCreated(holder: SurfaceHolder) {}
override fun surfaceChanged(
holder: SurfaceHolder,
format: Int,
width: Int,
height: Int
) {
mediaPlayer.setDisplay(holder)
//屏幕不关闭
mediaPlayer.setScreenOnWhilePlaying(true)
}
override fun surfaceDestroyed(holder: SurfaceHolder) {}
})
}
override fun onResume() {
super.onResume()
mediaPlayer.start()
lifecycleScope.launch {
while (!mediaPlayer.isPlaying){
mediaPlayer.start()
delay(500)
}
}
}
override fun onPause() {
super.onPause()
mediaPlayer.pause()
}
}
4. 播放列表
4.1 布局文件 fragment_video.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".VideoFragment">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/videoViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" />
</FrameLayout>
4.2 调用布局实现 VideoFragment.kt
private val videoUrls: List<String> = listOf(
"https://v-cdn.zjol.com.cn/280443.mp4",
"https://v-cdn.zjol.com.cn/276982.mp4",
"https://v-cdn.zjol.com.cn/276984.mp4",
"https://v-cdn.zjol.com.cn/276985.mp4",
"https://v-cdn.zjol.com.cn/276986.mp4",
"https://v-cdn.zjol.com.cn/276987.mp4",
"https://v-cdn.zjol.com.cn/276988.mp4",
"https://v-cdn.zjol.com.cn/276989.mp4",
"https://v-cdn.zjol.com.cn/276990.mp4",
"https://v-cdn.zjol.com.cn/276991.mp4",
"https://v-cdn.zjol.com.cn/276992.mp4",
"https://v-cdn.zjol.com.cn/276993.mp4",
"https://v-cdn.zjol.com.cn/276994.mp4",
"https://v-cdn.zjol.com.cn/276996.mp4",
"https://v-cdn.zjol.com.cn/276998.mp4",
"https://v-cdn.zjol.com.cn/277000.mp4",
"https://v-cdn.zjol.com.cn/277001.mp4",
"https://v-cdn.zjol.com.cn/277002.mp4",
"https://v-cdn.zjol.com.cn/277003.mp4",
"https://v-cdn.zjol.com.cn/277004.mp4"
)
class VideoFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_video, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val videoViewPager: ViewPager2 = view.findViewById(R.id.videoViewPager)
videoViewPager.apply {
adapter = object : FragmentStateAdapter(this@VideoFragment) {
override fun getItemCount() = videoUrls.size
override fun createFragment(position: Int) = PlayerFragment(videoUrls[position])
}
setCurrentItem(0, false)
// offscreenPageLimit = 5
}
}
}
5. 主页实现
5.1 布局文件, activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
tools:context=".MainActivity" >
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/mainViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="200dp"
android:layout_height="50dp"
android:layout_gravity="center_horizontal"
android:background="#00FFFFFF"
app:tabIndicatorFullWidth="false" />
</FrameLayout>
5.2 实现 VideoFragment 的调用, MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val tabLayout: TabLayout = findViewById(R.id.tabLayout)
val mainViewPackage2: ViewPager2 = findViewById(R.id.mainViewPager)
mainViewPackage2.apply {
adapter = object : FragmentStateAdapter(this@MainActivity) {
override fun getItemCount() = 3
override fun createFragment(position: Int) = when (position) {
1 -> VideoFragment()
else -> FooFragment()
}
}
setCurrentItem(1, false)
}
TabLayoutMediator(tabLayout, mainViewPackage2) { tab: TabLayout.Tab, i: Int ->
tab.text = when (i) {
1 -> "video"
else -> "foo"
}
}.attach()
}
}
6. 效果图