安卓自定义播报垂直滚动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
}
}