1、可见的第一个正在播放的视频item
滑向上如果超顶部时就停止,并且下一个视频会自动播放,是仿西瓜视频的。2、点击某一个正在播放的视频item
右下角的全屏(横屏没有上下滑动
)
在app
的build.gradle
在添加以下代码
1、implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.6'
,这个里面带的适配器,直接调用就即可
BaseRecyclerViewAdapterHelper
简称BRVAH
Android SDK |
是否支持BaseRecyclerViewAdapterHelper:3.0.6 |
---|---|
android compileSdkVersion 29 |
是 |
android compileSdkVersion 30 |
是 |
android compileSdkVersion 31 |
是 |
android compileSdkVersion 32 |
是 |
android compileSdkVersion 33 |
是 |
这依赖包还需要得到要添加,在Project
的build.gradle
在添加以下代码,不添加就不行
allprojects {
repositories {
...
maven { url "https://jitpack.io" }//加上
}
}
2、视频:implementation 'cn.jzvd:jiaozivideoplayer:7.0.5'
3、封面图:implementation 'com.github.bumptech.glide:glide:4.8.0'
1、增加网络权限
<uses-permission android:name="android.permission.INTERNET" />
2、增加配置
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:exported="true">
...
activity>
其中android:configChanges="orientation|screenSize|keyboardHidden"
是列表item
的视频横竖屏切换时,禁止activity
重新创建
MyPlayer.java
package com.example.myapplication3;
public class MyPlayer {
private String videoUrl;
private String coverImageUrl;
public MyPlayer(String videoUrl, String coverImageUrl) {
this.videoUrl = videoUrl;
this.coverImageUrl = coverImageUrl;
}
public String getVideoUrl() {
return videoUrl;
}
public void setVideoUrl(String videoUrl) {
this.videoUrl = videoUrl;
}
public String getCoverImageUrl() {
return coverImageUrl;
}
public void setCoverImageUrl(String coverImageUrl) {
this.coverImageUrl = coverImageUrl;
}
}
MyJzvdStd.kt
package com.example.myapplication3
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
import android.widget.SeekBar
import cn.jzvd.JzvdStd
/**
* 这里可以监听到视频播放的生命周期和播放状态
* 所有关于视频的逻辑都应该写在这里
* Created by Nathen on 2017/7/2.
*/
class MyJzvdStd : JzvdStd {
constructor(context: Context?) : super(context) {}
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {}
override fun init(context: Context) {
super.init(context)
}
override fun onClick(v: View) {
super.onClick(v)
val i = v.id
if (i == cn.jzvd.R.id.fullscreen) {
Log.i(TAG, "onClick: fullscreen button")
} else if (i == cn.jzvd.R.id.start) {
Log.i(TAG, "onClick: start button")
}
}
override fun onTouch(v: View, event: MotionEvent): Boolean {
super.onTouch(v, event)
val id = v.id
if (id == cn.jzvd.R.id.surface_container) {
when (event.action) {
MotionEvent.ACTION_UP -> {
if (mChangePosition) {
Log.i(TAG, "Touch screen seek position")
}
if (mChangeVolume) {
Log.i(TAG, "Touch screen change volume")
}
}
}
}
return false
}
override fun getLayoutId(): Int {
return cn.jzvd.R.layout.jz_layout_std
}
override fun startVideo() {
super.startVideo()
Log.i(TAG, "startVideo")
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
super.onStopTrackingTouch(seekBar)
Log.i(TAG, "Seek position ")
}
override fun gotoScreenFullscreen() {
super.gotoScreenFullscreen()
Log.i(TAG, "goto Fullscreen")
}
override fun gotoScreenNormal() {
super.gotoScreenNormal()
Log.i(TAG, "quit Fullscreen")
}
override fun autoFullscreen(x: Float) {
super.autoFullscreen(x)
Log.i(TAG, "auto Fullscreen")
}
override fun onClickUiToggle() {
super.onClickUiToggle()
Log.i(TAG, "click blank")
}
//onState 代表了播放器引擎的回调,播放视频各个过程的状态的回调
override fun onStateNormal() {
super.onStateNormal()
}
override fun onStatePreparing() {
super.onStatePreparing()
}
override fun onStatePlaying() {
super.onStatePlaying()
}
override fun onStatePause() {
super.onStatePause()
}
override fun onStateError() {
super.onStateError()
}
override fun onStateAutoComplete() {
super.onStateAutoComplete()
Log.i(TAG, "Auto complete")
}
//changeUiTo 真能能修改ui的方法
override fun changeUiToNormal() {
super.changeUiToNormal()
}
override fun changeUiToPreparing() {
super.changeUiToPreparing()
}
override fun changeUiToPlayingShow() {
super.changeUiToPlayingShow()
}
override fun changeUiToPlayingClear() {
super.changeUiToPlayingClear()
}
override fun changeUiToPauseShow() {
super.changeUiToPauseShow()
}
override fun changeUiToPauseClear() {
super.changeUiToPauseClear()
}
override fun changeUiToComplete() {
super.changeUiToComplete()
}
override fun changeUiToError() {
super.changeUiToError()
}
override fun onInfo(what: Int, extra: Int) {
super.onInfo(what, extra)
}
override fun onError(what: Int, extra: Int) {
super.onError(what, extra)
}
}
播放器适配器PlayerAdapter.kt
,这里第一个视频开始播放,其他的未播放
package com.example.myapplication3.adapter
import android.widget.ImageView
import cn.jzvd.JzvdStd
import com.bumptech.glide.Glide
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.example.myapplication3.MyPlayer
import com.example.myapplication3.R
import kotlinx.android.synthetic.main.item_recyclerview.view.*
class PlayerAdapter(layoutResId: Int = R.layout.item_recyclerview) :
BaseQuickAdapter<MyPlayer, BaseViewHolder>(layoutResId) {
override fun convert(holder: BaseViewHolder, item_url: MyPlayer) {
holder.itemView.run {
videoplayer.setUp(item_url.videoUrl,"",JzvdStd.SCREEN_NORMAL)
videoplayer.thumbImageView.scaleType = ImageView.ScaleType.FIT_XY
// videoplayer.thumbImageView.scaleType = ImageView.ScaleType.FIT_CENTER
//第一个视频开始播放,其他的未播放
if ( 0 == holder.adapterPosition){
videoplayer.startVideo()
}
Glide.with(videoplayer.context).load(item_url.coverImageUrl).into(videoplayer.thumbImageView)
}
}
}
item
布局item_recyclerview.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="300dp">
<com.example.myapplication3.MyJzvdStd
android:id="@+id/videoplayer"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
RelativeLayout>
1、视频地址
videoplayer.setUp("视频地址".videoUrl,"",JzvdStd.SCREEN_NORMAL)
2、封面图地址
Glide.with(videoplayer.context).load("封面图地址".coverImageUrl).into(videoplayer.thumbImageView)
3、如何使用jiaozivideoplayer
播放本地视频
注意:jiaozivideoplayer
支持file
:///开头的文件播放,但是不支持assets
或者raw
目录下的视频,assets
下的视频要先复制到本地路经才能播放
MainActivity.kt
,在我们滑动的时候,jiaozivideoplayer
会自动停止正在播放的视频,这里面我还添加了一个功能,就是监听当滑动停止的时候自动播放下一个视频
package com.example.myapplication3
import android.content.Context
import android.graphics.Rect
import android.os.Bundle
import android.view.KeyEvent
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import cn.jzvd.Jzvd
import com.example.myapplication3.adapter.PlayerAdapter
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
private val mAdapter by lazy {
PlayerAdapter().apply {
}
}
//视频
private val videoUrl = "http://gslb.miaopai.com/stream/ed5HCfnhovu3tyIQAiv60Q__.mp4"
// private val videoUrl = "https://vd4.bdstatic.com/mda-jbppbefbbztvws50/sc/mda-jbppbefbbztvws50.mp4"
//封面图
private val coverImageUrl =
"https://img1.baidu.com/it/u=265818744,2982786856&fm=253&fmt=auto&app=120&f=JPEG?w=1422&h=800"
private val mList: MutableList<MyPlayer> = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
init()
}
private fun init() {
for (i in 0..19) {
val video = MyPlayer(videoUrl, coverImageUrl)
mList.add(video);
}
val layoutManager = LinearLayoutManager(this@MainActivity)
layoutManager.orientation = LinearLayoutManager.VERTICAL
recyclerview.layoutManager = layoutManager
recyclerview.adapter = mAdapter
mAdapter.setList(mList)
recyclerview.addOnScrollListener(AutoPlayScrollListener(this@MainActivity))
}
/**
* 监听recycleView滑动状态,
* 自动播放可见区域内的第一个视频
*/
private class AutoPlayScrollListener(private val context: Context) : RecyclerView.OnScrollListener() {
private var firstVisibleItem = 0
private var lastVisibleItem = 0
private var visibleCount = 0
/**
* 被处理的视频状态标签
*/
private enum class VideoTagEnum {
/**
* 自动播放视频
*/
TAG_AUTO_PLAY_VIDEO,
/**
* 暂停视频
*/
TAG_PAUSE_VIDEO
}
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
when (newState) {
RecyclerView.SCROLL_STATE_IDLE -> autoPlayVideo(
recyclerView,
VideoTagEnum.TAG_AUTO_PLAY_VIDEO
)
RecyclerView.SCROLL_STATE_DRAGGING, RecyclerView.SCROLL_STATE_SETTLING -> {}
else -> {}
}
}
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val layoutManager = recyclerView.layoutManager
if (layoutManager is LinearLayoutManager) {
val linearManager = layoutManager
firstVisibleItem = linearManager.findFirstVisibleItemPosition()
lastVisibleItem = linearManager.findLastVisibleItemPosition()
visibleCount = lastVisibleItem - firstVisibleItem
}
}
/**
* 循环遍历可见区域的播放器
* 然后通过 getLocalVisibleRect(rect)方法计算出哪个播放器完全显示出来
* @param recyclerView
* @param handleVideoTag 视频需要进行状态
*/
private fun autoPlayVideo(recyclerView: RecyclerView?, handleVideoTag: VideoTagEnum) {
for (i in 0 until visibleCount) {
if (recyclerView != null && recyclerView.getChildAt(i) != null && recyclerView.getChildAt(i).findViewById<MyJzvdStd>(R.id.videoplayer) != null) {
val homeGSYVideoPlayer = recyclerView.getChildAt(i).findViewById<MyJzvdStd>(R.id.videoplayer) as MyJzvdStd
val rect = Rect()
homeGSYVideoPlayer.getLocalVisibleRect(rect)
val videoheight = homeGSYVideoPlayer.height
if (rect.top == 0 && rect.bottom == videoheight) {
handleVideo(handleVideoTag, homeGSYVideoPlayer)
// 跳出循环,只处理可见区域内的第一个播放器
break
}
}
}
}
/**
* 视频状态处理
*
* @param handleVideoTag 视频需要进行状态
* @param homeGSYVideoPlayer JZVideoPlayer播放器
*/
private fun handleVideo(handleVideoTag: VideoTagEnum, homeGSYVideoPlayer: MyJzvdStd) {
when (handleVideoTag) {
VideoTagEnum.TAG_AUTO_PLAY_VIDEO -> if (homeGSYVideoPlayer.state !== Jzvd.STATE_PLAYING) {
// 进行播放
homeGSYVideoPlayer.startVideo()
}
VideoTagEnum.TAG_PAUSE_VIDEO -> if (homeGSYVideoPlayer.state !== Jzvd.STATE_PAUSE) {
// 模拟点击,暂停视频
homeGSYVideoPlayer.startButton.performClick()
}
else -> {}
}
}
}
/**
* 拦截返回键 返回不退出程序
*/
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
if (Jzvd.backPress()) {
return true
} else {
if (keyCode == KeyEvent.KEYCODE_BACK) {
moveTaskToBack(true)
return true
}
}
return super.onKeyDown(keyCode, event)
}
}
activity_main.xml
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" />