安卓自定义播报垂直滚动view

2019-05-27  本文已影响0人  李云龙_

1. 连续滚动

原理

通过 view.post(Runnable()) 每次发消息,每次接收消息时 recyclerView.scrollBy(offset)

代码

class AutoScrollRecyView(context: Context, attrs: AttributeSet?) : RecyclerView(context, attrs) {

    internal var autoPollTask: AutoPollTask
    private var running: Boolean = false //标示是否正在自动轮询
    private var canRun: Boolean = false//标示是否可以自动轮询,可在不需要的是否置false


    init {
        autoPollTask = AutoPollTask(this)
    }

    internal class AutoPollTask//使用弱引用持有外部类引用->防止内存泄漏
    (reference: AutoScrollRecyView) : Runnable {
        var y: Int = 0
        private val mReference: WeakReference<AutoScrollRecyView>

        init {
            this.mReference = WeakReference(reference)
        }

        override fun run() {
            val recyclerView = mReference.get()
            if (recyclerView != null && recyclerView.running && recyclerView.canRun) {
//                y += 1
//                if (y % ((recyclerView.context.resources.getDimension(R.dimen.dp_30)).toInt()) == 0) {
//                    recyclerView.postDelayed(recyclerView.autoPollTask, 2000)
//                    return
//                }
                recyclerView.scrollBy(2, 1)
                recyclerView.postDelayed(recyclerView.autoPollTask, TIME_AUTO_POLL)
            }
        }
    }

    //开启:如果正在运行,先停止->再开启
    fun start() {
        if (running)
            stop()
        canRun = true
        running = true
        postDelayed(autoPollTask, TIME_AUTO_POLL)
    }

    fun stop() {
        running = false
        removeCallbacks(autoPollTask)
    }

    override fun onTouchEvent(e: MotionEvent): Boolean {
        when (e.action) {
            MotionEvent.ACTION_DOWN -> if (running)
                stop()
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_OUTSIDE -> if (canRun)
                start()
        }
        return super.onTouchEvent(e)
    }

    companion object {
        private val TIME_AUTO_POLL: Long = 16
    }
}

2. 每隔2秒滚动一次,每次滚动用时400ms

原理

通过 view.post(Runnable()) 每次发消息,每次接收消息时使用 ValueAnimator 开启动画,动画持续时间为滚动时间,并不是真的进行动画,而是使用其每次的差值,通过与上一次动画差值相减得到当前需要 recyclerView.scrollBy(offset) 的 offset 距离,动画结束继续 view.post(Runnable()) 发送消息

代码
class AutoPullRecy3(context: Context, attrs: AttributeSet?) : RecyclerView(context, attrs) {

    internal var autoPollTask: AutoPollTask
    private var running: Boolean = false //标示是否正在自动轮询
    private var canRun: Boolean = false//标示是否可以自动轮询,可在不需要的是否置false


    init {
        autoPollTask = AutoPollTask(this)
    }

    internal class AutoPollTask//使用弱引用持有外部类引用->防止内存泄漏
    (reference: AutoPullRecy3) : Runnable {
        var y: Int = 0
        private val mReference: WeakReference<AutoPullRecy3>

        init {
            this.mReference = WeakReference(reference)
        }

        override fun run() {
            val recyclerView = mReference.get()
            if (recyclerView != null && recyclerView.running && recyclerView.canRun) {
                var offsetHeight = recyclerView.getChildAt(0).height
                recyclerView.startMoveAnim(recyclerView, offsetHeight)
            }
        }
    }

    fun startMoveAnim(recyView: AutoPullRecy3, offset: Int) {
        val animator = ValueAnimator.ofInt(0, offset)
        animator.setTarget(recyView)
        animator.addUpdateListener(object : ValueAnimator.AnimatorUpdateListener {
            private var lastDs: Int = 0
            override fun onAnimationUpdate(animation: ValueAnimator) {
                val value = animation.animatedValue as Int
                Log.e("TAG", "animatedValue=" + value + " lastDs=" + lastDs)
                var realScrollYDistance = (value - lastDs)
                Log.e("TAG", "realScrollYDistance=" + realScrollYDistance)
                recyView.scrollBy(2, realScrollYDistance)
                lastDs = value
            }
        })
        animator.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator) {
                super.onAnimationEnd(animation)
                recyView.postDelayed(recyView.autoPollTask, TIME_AUTO_POLL) //动画结束时再发一次
            }
        }
        )
        animator.setDuration(SCROLL_TIME)
        animator.start()
    }

    //开启:如果正在运行,先停止->再开启
    fun start() {
        if (running)
            stop()
        canRun = true
        running = true
        postDelayed(autoPollTask, TIME_AUTO_POLL)
    }

    fun stop() {
        running = false
        removeCallbacks(autoPollTask)
    }

    override fun onTouchEvent(e: MotionEvent): Boolean {
        when (e.action) {
            MotionEvent.ACTION_DOWN -> if (running)
                stop()
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_OUTSIDE -> if (canRun)
                start()
        }
        return super.onTouchEvent(e)
    }

    companion object {
        private val TIME_AUTO_POLL: Long = 2000
        private val SCROLL_TIME: Long = 400
    }
}

上一篇 下一篇

猜你喜欢

热点阅读