Android实现无限循环滚动弹幕的代码示例

 更新时间:2024年08月01日 08:23:07   作者:NullPointerExcept997  
这篇文章主要介绍了android实现无限循环滚动的弹幕
,文中通过代码示例讲解的非常详细,对大家实现循环弹幕有一定的帮助,需要的朋友可以参考下

先上效果图

要实现上面的效果,我们先拆分下实现要素:

  • 1、弹幕布局是从屏幕的右侧向左侧滚动,单个弹幕之间的间距是固定的,并且滚动速度需要匀速
  • 2、弹幕要支持无限滚动,出于性能要求,如果不在屏幕内的,应该移除,不能无限追加到内存里面。

思路

  • 1、对于滚动和超出屏幕后移除,可以使用动画来实现,动画从屏幕右边开始移动到屏幕左边,监听如果已经动画结束,则remove掉布局。

  • 2、无限循环效果,可以使用两个链表实现,一个保存加入到屏幕的弹幕数据(A),另一个保存未添加到屏幕的弹幕数据(B)。让进入屏幕前将布局从B中poll出来,添加到A中。反之,屏幕移除的时候从A中poll出来,添加到B中。

实现

1.无线滚动 需要两个链表 mDanMuList初始包含所有弹幕数据 mVisibleDanMuList每次取出mDanMuList第一条数据 填充到弹幕 直到弹幕动画结束后,再重新添加到mDanMuList里

//为展示在屏幕上的弹幕数据 private val mDanMuList = LinkedList<BulletChatDetail>()
//屏幕中展示的弹幕数据 private val mVisibleDanMuList = LinkedList<BulletChatDetail>()
fun enqueueDanMuList(danMuList: List<BulletChatDetail>?) {
    danMuList?.forEach {         
	if (this.mDanMuList.contains(it).not()) {
            this.mDanMuList.add(it)
        }
    }    
	if (mWidth == 0) {
        viewTreeObserver.addOnGlobalLayoutListener(object :
                ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                mWidth = measuredWidth                
				viewTreeObserver.removeOnGlobalLayoutListener(this)

                if (mIsRunning.get().not()) {
                    mDanMuList.poll()?.apply {                       
					//这里是用来处理布局的交替工作,前面分析有说明                         					                           mVisibleDanMuList.add(this)
                        createDanMuItemView(this)
                    }                
				}
            }
        })
    } else {
        if (mIsRunning.get().not()) {
            mDanMuList.poll()?.apply {                 
			//这里是用来处理布局的交替工作,前面分析有说明                 
			mVisibleDanMuList.add(this)
            createDanMuItemView(this)
            }        
			}
    }
}

2.添加动画 每个弹幕默认都是头像加描述组成 所以自定义一个DanMuItemView 内部就一个填充数据的方法

class DanMuItemView @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : LinearLayoutCompat(context, attrs, defStyleAttr) {

    var danMu: BulletChatDetail? = null     
	private val mBinding: DanmuItemBinding      
	init {
        mBinding = DanmuItemBinding.inflate(
                LayoutInflater.from(context), this, true         )
    }

    fun setDanMuEntity(danmu: BulletChatDetail?) {
        this.danMu = danmu
        mBinding.tvDanMuItem.text = danmu?.bulletChat            	  	 mBinding.ivDanMuItem.setCircleImageUrl(danmu?.userLogo?.toCompleteImageUrl(3))
        measure(0, 0)
    }
}

3.监听viewtree树,当布局初始化完成后,创建弹幕view,并开启动画 DanMuItemView的位置 默认在-danMuItemView.measuredWidth 负弹幕view的宽度

private fun createDanMuItemView(DanMu: BulletChatDetail) {
    val danMuItemView = DanMuItemView(context).apply {         
	setDanMuEntity(DanMu)
    }     //这里将布局添加之后,默认便宜到屏幕右侧出屏幕,造成布局总是从右👉移动到👈左的效果。    
	val param = LayoutParams(danMuItemView.measuredWidth, danMuItemView.measuredHeight)
    param.gravity = Gravity.CENTER_VERTICAL    
	param.leftMargin = mWidth     
	startDanMuAnimate(danMuItemView)
    addView(danMuItemView, param)
}

4 .开启动画 view默认有动画的方法 我们已知view移动的距离为 屏幕宽度+弹幕view 需要匀速120.0f // 你想要的目标速度,单位是像素每秒 所以时间得动态计算 并且我们知道每个弹幕间ui的间距 所以监听弹幕view匀速动画所在的位置 当滚动进入屏幕的距离刚好是自身+间距的20dp时,就开启第二个弹幕item的动画 这样就实现了无限弹幕

val targetSpeedPxPerSecond = 120.0f // 你想要的目标速度,单位是像素每秒 
val totalTranslateX = ((mWidth + danMuItemView.measuredWidth)).toFloat()
val duration = (totalTranslateX / targetSpeedPxPerSecond * 1000).toLong() // 转换为毫秒
var isInit = false 
danMuItemView.animate()
       //注意这边设置的便宜量是容器布局的宽度+弹幕item布局的宽度,这样就确保滚动值刚好是从屏幕右侧外到屏幕左侧外         .translationXBy(-totalTranslateX)
        .setDuration(duration)
        .setInterpolator(LinearInterpolator())
        .setUpdateListener {              
		val danMuTranslateX =(mWidth + danMuItemView.measuredWidth) * (it.animatedValue as Float)
        //这里是关键,用来确保每个item布局的间距一致,判断如果滚动进入屏幕的距离刚好是自身+20dp,也就是刚好空出来了20dp之后,紧接着下一个弹幕布局开始添加并动起来。             
			if (danMuTranslateX >= danMuItemView.measuredWidth +
                    DensityUtils.dp2px(15f) && isInit.not()) {
                isInit = true                
				if (mDanMuList.size == 0) {
                    mHasStopRun = true                 
					}else{
                    mHasStopRun = false                    
					mDanMuList.poll()?.apply {                     
					mVisibleDanMuList.add(this)
                        createDanMuItemView(this)
                    }                
				}
            }
        }         
		.setListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator) {
                super.onAnimationEnd(animation)
                if (mIsRunning.get().not()) {
                    mIsRunning.set(true)
                }
                //很重要,在动画结束,也就是布局从屏幕移除之后,切记从布局中移除掉,                 
				//并且进行一波数据交替,方便实现无线循环                
				danMuItemView.danMu?.let {                    
				mVisibleDanMuList.remove(it)
                    mDanMuList.add(it)
                }                
				YzLog.e("mHasStopRun->>>>${mHasStopRun}")
                if (mHasStopRun) {
                    createDanMu()
                }else{
                    removeView(danMuItemView)
                }
            }
        }).start()

当数据只有一两个的时候,需要添加一个变量来控制 比如如果弹幕数据源只有两条数据,当两条弹幕更好在同一屏幕出现此时弹幕数据源为空,可见数据源为两条,当第二条弹幕滚动到符合添加第三条数据的位置时,此时数据源已经没有数据了,需要将参数置为true,等到第二条数据动画结束时,重新走添加弹幕逻辑。具体事项在上面代码已经展示

以上就是Android实现无限循环滚动弹幕的代码示例的详细内容,更多关于Android无限循环滚动弹幕的资料请关注脚本之家其它相关文章!

相关文章

  • 深入Android Handler与线程间通信ITC的详解

    深入Android Handler与线程间通信ITC的详解

    本篇文章是对Android的Handler与线程间通信ITC进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • 基于Android实现跳转到WiFi开关设置页的详细步骤

    基于Android实现跳转到WiFi开关设置页的详细步骤

    在Android应用开发中,有时候需要引导用户到特定的系统设置页面,例如Wi-Fi开关设置页,可以通过隐式Intent来实现这一功能,以下是详细的步骤以及相关的Kotlin代码示例,需要的朋友可以参考下
    2024-09-09
  • Android巧用DecorView实现对话框功能

    Android巧用DecorView实现对话框功能

    本篇文章主要介绍了Android巧用DecorView实现对话框功能,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-04-04
  • Android入门之ListView应用解析(二)

    Android入门之ListView应用解析(二)

    这篇文章主要介绍了Android入门之ListView应用,继上一篇之后将对Android的ListView用法做更深入的剖析,需要的朋友可以参考下
    2014-08-08
  • Android编程显示网络上的图片实例详解

    Android编程显示网络上的图片实例详解

    这篇文章主要介绍了Android编程显示网络上的图片,结合实例形式详细分析了Android显示网络图片的流程与具体操作技巧,需要的朋友可以参考下
    2016-10-10
  • Android实现强制下线功能的示例代码

    Android实现强制下线功能的示例代码

    这篇文章主要介绍了Android实现强制下线功能的示例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • 如何利用matrix实现图片倒影效果

    如何利用matrix实现图片倒影效果

    利用matrix可以实现各种图片的特效,比如图片的旋转、缩放、移动,甚至是图片倒影效果,这篇文章为大家介绍了matrix实现图片倒影的代码,感兴趣的小伙伴们可以参考一下
    2016-05-05
  • Flutter路由跳转参数处理技巧详解

    Flutter路由跳转参数处理技巧详解

    这篇文章主要为大家介绍了Flutter路由跳转参数处理技巧示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • Android非XML形式动态生成、调用页面的方法

    Android非XML形式动态生成、调用页面的方法

    这篇文章主要介绍了Android非XML形式动态生成、调用页面的方法,涉及Android构建页面的相关技巧,需要的朋友可以参考下
    2015-04-04
  • RecyclerView底部分割线去除的方法

    RecyclerView底部分割线去除的方法

    如何完美的去除RecyclerView底部分割线?这篇文章主要为大家详细介绍了RecyclerView底部分割线去除的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04

最新评论