Android实现循环轮播跑马灯的效果

 更新时间:2023年05月04日 10:42:59   作者:Calculus_小王  
这篇文章主要介绍了为大家详细介绍了如何通过Android实现循环轮播跑马灯的效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

先看效果

支持暂停,恢复,view自定义和池化回收复用。使用上,只需要引入xml,并绑定factory即可,内部会在attach时自动开始

 <MarqueeAnimalView
        android:id="@+id/marqueeView"
        android:layout_width="200dp"
        android:layout_height="30dp"
        android:background="@color/color_yellow" />
val list = mutableListOf("我是跑马灯1", "我不是跑马灯", "你猜我是不是跑马灯")
var position = 0
view.marqueeView.setFactory(object : PoolViewFactory {
    override fun makeView(layoutInflater: LayoutInflater, parent: ViewGroup): View {
        val view = TextView(this@ViewActivity)
        view.setPadding(0, 0, 20.dp(), 0)
        view.textSize = 12f
        view.setTextColor(ResourceUtil.getColor(R.color.white))
        return view
    }
    override fun setAnimator(objectAnimator: ObjectAnimator, width: Int, parentWidth: Int) {
        objectAnimator.duration = (parentWidth + width) * 5L
    }
    override fun setView(view: View): Boolean {
        (view as? TextView)?.text = list[position++ % list.size]
        return true
    }
})

池化思路

参考Message的思路,对view进行回收复用,避免内存持续增长,增大GC压力

private fun obtain(): View? {
    synchronized(sPoolSync) {
        if (!isAttachedToWindow) {
            return null
        }
        if (queue.isNotEmpty()) {
            return queue.poll()
        }
    }
    return factory?.makeView(layoutInflater, this@MarqueeAnimalView)?.apply {
        addView(this, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
    }
}
private fun recycle(view: View) {
    synchronized(sPoolSync) {
        if (queue.size < MAX_POOL_SIZE) {
            queue.offer(view)
        }
    }
}

创造工厂

这里的思路源于ViewSwitchFactory

interface PoolViewFactory {
    fun makeView(layoutInflater: LayoutInflater, parent: ViewGroup): View
    fun setAnimator(objectAnimator: ObjectAnimator, width: Int, parentWidth: Int)
    /**
     * 返回值,代表view是否需要重新测量
     */
    fun setView(view: View): Boolean
}

轮询切换

这里根据对动画进行初始化,并设置合适的监听。此时需要获取当view和parent的width,以用于标定始末位置,需要注意x轴的正负方向。animators用于存储开始的动画,这也是设计时存在的遗留问题,因为主动取消所有动画,但view->animator是单向绑定关系,所以需要保存发生的动画

private val animators = hashMapOf<String, ObjectAnimator>()
private fun next(view: View?) {
    view ?: return
    if (factory?.setView(view) == true) {
        view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED))
    }
    val width = view.measuredWidth
    val parentWidth = measuredWidth
    val targetValue = parentWidth - width
    val animator = ObjectAnimator.ofFloat(view, PROPERTY_NAME, parentWidth.toFloat(), -width.toFloat()).apply {
        // null即为默认线性插值器
        interpolator = null
        addUpdateListener(
            RecyclerAnimatorUpdateListener(targetValue) {
                next(obtain())
                removeUpdateListener(it)
            }
        )
        addListener(this@MarqueeAnimalView)
        factory?.setAnimator(this, width, parentWidth)
    }
    animators["${view.hashCode()}-${animator.hashCode()}"] = animator
    animator.start()
}

动画监听

当动画结束时,需要对view进行回收,并对动画移除。取消动画时,需要将view强制归位

同时,为了方便使用,OnAttachStateChangeListener使得整体动画更加平滑,也避免了view不可见时,动画仍然在持续执行浪费资源。当然如fragment不可见时的监听需要完善

override fun onAnimationEnd(animation: Animator?) {
    (animation as? ObjectAnimator)?.let { animator ->
        (animator.target as? View)?.let { view ->
            animators.remove("${view.hashCode()}-${animator.hashCode()}")
            recycle(view)
        }
        // target释放
        animator.target = null
    }
}
override fun onAnimationCancel(animation: Animator?) {
    (animation as? ObjectAnimator)?.let { animator ->
        (animator.target as? View)?.let { view ->
            view.translationX = measuredWidth.toFloat()
        }
    }
}
override fun onViewAttachedToWindow(v: View?) {
    if (animators.isNotEmpty()) {
        resume()
    } else {
        start()
    }
}
override fun onViewDetachedFromWindow(v: View?) {
    pause()
}

对外能力

fun start() {
    if (measuredWidth == 0) {
        this.post {
            // 如果测量还未完成,那就等待post后发起
            next(obtain())
        }
        return
    }
    next(obtain())
}
fun stop() {
    val it = animators.values.iterator()
    while (it.hasNext()) {
        val i = it.next()
        it.remove()
        i.cancel()
    }
}
fun pause() {
    for (i in animators.values) {
        i.pause()
    }
}
fun resume() {
    for (i in animators.values) {
        i.resume()
    }
}

完整代码

欢迎支持,搜索MarqueeAnimalView即可 github.com/wjf-962464/Self_Demo.git

到此这篇关于Android实现循环轮播跑马灯的效果的文章就介绍到这了,更多相关Android跑马灯内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Android布局之表格布局TableLayout详解

    Android布局之表格布局TableLayout详解

    这篇文章主要为大家详细介绍了Android布局之表格布局TableLayout,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10
  • Android仿微信布局的实现示例

    Android仿微信布局的实现示例

    本文主要介绍了Android仿微信布局的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • 浅析Android手机卫士关闭自动更新

    浅析Android手机卫士关闭自动更新

    保存数据的四种方式,网络,广播提供者,SharedPreferences,数据库。接下来通过本文给大家介绍android手机卫士关闭自动更新的相关知识,感兴趣的朋友一起学习吧
    2016-04-04
  • Android开发之ImageSwitcher相册功能实例分析

    Android开发之ImageSwitcher相册功能实例分析

    这篇文章主要介绍了Android开发之ImageSwitcher相册功能,结合实例形式分析了Android ImageSwitcher相册的原理、使用方法及相关操作注意事项,需要的朋友可以参考下
    2019-03-03
  • 一文带你搞清楚Android游戏发行切包资源ID那点事

    一文带你搞清楚Android游戏发行切包资源ID那点事

    这篇文章主要介绍了Android 解决游戏发行切包资源ID的一些问题,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下
    2023-05-05
  • 安卓逆向腾讯动漫app返回数据加密分析案例分享

    安卓逆向腾讯动漫app返回数据加密分析案例分享

    这篇文章主要为大家介绍了安卓逆向腾讯动漫app返回数据加密分析的案例分享,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-02-02
  • Android编程ProgressBar自定义样式之动画模式实现方法

    Android编程ProgressBar自定义样式之动画模式实现方法

    这篇文章主要介绍了Android编程ProgressBar自定义样式之动画模式实现方法,涉及Android动画模式的布局技巧,非常具有实用价值,需要的朋友可以参考下
    2015-10-10
  • Android RenderScript高斯模糊

    Android RenderScript高斯模糊

    这篇文章主要介绍了Android RenderScript高斯模糊的相关代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-11-11
  • 给大家分享一些安卓自学心得

    给大家分享一些安卓自学心得

    本文是笔者在学习安卓开发的过程中的一些经验之谈的分享,希望对大家学习安卓开发能够有所帮助。
    2015-12-12
  • Android 侧滑抽屉菜单的实现代码

    Android 侧滑抽屉菜单的实现代码

    这篇文章主要介绍了Android 侧滑抽屉菜单的实现代码,本文通过实例图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03

最新评论