2023年7月15日发(作者:)
实现⼀个横向⽆限循环滚动的单⾏弹幕效果本期将带领⼤家实现⼀个这样的效果,⽀持⽆限循环的单⾏弹幕效果。实现思路分析要实现上⾯的效果,我们先拆分下实现要素:1、弹幕布局是从屏幕的右侧向左侧滚动,单个弹幕之间的间距是固定的(设计要求)2、弹幕要⽀持⽆限滚动,出于性能要求,如果不在屏幕内的,应该移除,不能⽆限追加到内存⾥⾯。拆分完需求要素之后,针对上⾯的需求要素,做⼀下思路解答:1、对于滚动和超出屏幕后移除,可以使⽤动画来实现,动画从屏幕右边开始移动到屏幕左边,监听如果已经动画结束,则remove掉布局。2、⽆限循环效果,可以使⽤两个链表实现,⼀个保存加⼊到屏幕的弹幕数据(A),另⼀个保存未添加到屏幕的弹幕数据(B)。让进⼊屏幕前将布局从B中poll出来,添加到A中。反之,屏幕移除的时候从A中poll出来,添加到B中。代码实现⾸先创建出来⼀个弹幕数据对象类data class Danmu( //头像 var headerUrl: String? = null, //昵称 var userName: String? = null, //信息 var info: String? = null,)要被使⽤的弹幕itemViewclass DanmuItemView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : LinearLayoutCompat(context, attrs, defStyleAttr) { private var danmuItemView: TextView? = null var danmu: Danmu? = null init { (context).inflate(_item, this, true) danmuItemView = findViewById(uItem) } fun setDanmuEntity(danmu: Danmu) { = danmu danmuItemView?.text = "我是⼀个弹幕~~~~~哈哈哈哈哈哈" + me measure(0, 0) }}接下来就是弹幕布局的容器类,⽤来控制动画和数据交替。注意代码中有很有⽤的注释class DanmuView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : FrameLayout(context, attrs, defStyleAttr) { private var mWidth = 0 //为展⽰在屏幕上的弹幕数据 private val mDanMuList = LinkedList() //屏幕中展⽰的弹幕数据 private val mVisibleDanMuList = LinkedList() //判断是否在运⾏ private val mIsRunning = AtomicBoolean(false) override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { ure(widthMeasureSpec, heightMeasureSpec) mWidth = measuredWidth } /** *
添加弹幕数据 */ fun enqueueDanMuList(danMuList: ArrayList) { h { if (ns(it).not()) { (it) } } if (mWidth == 0) { lobalLayoutListener(object : alLayoutListener { override fun onGlobalLayout() { mWidth = measuredWidth OnGlobalLayoutListener(this) if (().not()) { ()?.apply { //这⾥是⽤来处理布局的交替⼯作,前⾯分析有说明 (this) createDanMuItemView(this) } } } }) } else { if (().not()) { ()?.apply { //这⾥是⽤来处理布局的交替⼯作,前⾯分析有说明 (this) createDanMuItemView(this) } } } } private fun startDanMuAnimate(danMuItemView: DanmuItemView) { var isInit = false e() //注意这边设置的便宜量是容器布局的宽度+弹幕item布局的宽度,这样就确保滚动值刚好是从屏幕右侧外到屏幕左侧外 .translationXBy((-(mWidth + edWidth)).toFloat()) .setDuration(6000) .setInterpolator(LinearInterpolator()) .setUpdateListener { .setUpdateListener { val danMuTranslateX = (mWidth + edWidth) * (edValue as Float) //这⾥是关键,⽤来确保每个item布局的间距⼀致,判断如果滚动进⼊屏幕的距离刚好是⾃⾝+20dp,也就是刚好空出来了20dp之后,紧接着下⼀个弹幕布局开始添加并动起来。 if (danMuTranslateX >= edWidth + tDpToPixel(20F) && ()) { isInit = true ()?.apply { (this) createDanMuItemView(this) } } } .setListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator?) { if (().not()) { (true) } //很重要,在动画结束,也就是布局从屏幕移除之后,切记从布局中移除掉, //并且进⾏⼀波数据交替,⽅便实现⽆线循环 ?.let { (it) (it) } removeView(danMuItemView) } }).start() } private fun createDanMuItemView(danMu: Danmu) { val danMuItemView = DanmuItemView(context).apply { setDanmuEntity(danMu) } //这⾥将布局添加之后,默认便宜到屏幕右侧出屏幕,造成布局总是从右
发布者:admin,转转请注明出处:http://www.yc00.com/news/1689429104a246736.html
评论列表(0条)