现在来给viewpager实现的banenr加上自动轮播
自动轮播的原理,使用handler的延迟消息来实现。
自动轮播实现如下内容
开始轮播&停止轮播
可配置轮播时长、轮播方向
通过自定义属性来配置轮播时长,方向
感知生命周期,可见时开始轮播,不可见时停止轮播
感知手指触摸,触摸按下时停止轮播,抬起重新计时
banner对外提供接口,开始轮播
fun startLoop(){ } fun stopLoop(){ }
定义handler实现轮播
// 创建handler fun startLoop() { if (loopHandler == null) { loopHandler = Handler(Looper.getMainLooper()) { message -> return@Handler when (message.what) { LOOP_NEXT -> { // 定义消息处理 loopNext() true } else -> false } } } // 移除正在轮播的消息 loopHandler?.removeMessages(LOOP_NEXT) // 发送延迟轮播的消息 loopHandler?.sendEmptyMessageDelayed(LOOP_NEXT, mLoopDuration) } private fun loopNext() { val count = adapter?.count ?: 0 // 当pager数量为0或者1时,不用轮播 if (count in 0..1) return val curr = when (currentItem) { in 0..count - 2 -> { currentItem + 1 } count - 1 -> 0 else -> 0 } setCurrentItem(curr, true) loopHandler?.sendEmptyMessageDelayed(LOOP_NEXT, mLoopDuration) }
定义接口
/** * 设置轮播时长,有效数据必须大于0,否则使用默认数据5S * @param duration Long */ fun setLoopDuration(duration: Long) { if (duration < 0) { // 小于0的数据认为是非法数据,使用默认设置 return } this.mLoopDuration = duration } /** * 设置轮播方向,默认[LoopOrientation.LTR] * @param orientation Int */ fun setLoopOrientation(@LoopOrientation orientation: Int) { this.mLoopOrientation = orientation }
轮播处理参数
private fun loopNext() { val count = adapter?.count ?: 0 // 当pager数量为0或者1时,不用轮播 if (count in 0..1) return val curr = when (mLoopOrientation) { LoopOrientation.RTL -> { when (currentItem) { in 1..count - 1 -> { currentItem - 1 } else -> count - 1 // 0 } } else -> { when (currentItem) { in 0..count - 2 -> { currentItem + 1 } else -> 0 // count - 1 } } } setCurrentItem(curr, true) mLoopHandler?.sendEmptyMessageDelayed(LOOP_NEXT, mLoopDuration) }
<resources> <declare-styleable name="VPBanner"> <attr name="vp_loop_duration" format="integer" /> <attr name="vp_loop_orientation" format="enum" > <enum name="ltr" value="1" /> <enum name="rtl" value="0" /> </attr> <attr name="vp_auto_loop" format="boolean" /> </declare-styleable> </resources>
读取属性
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { // 读取自定义的属性 val typedArray = context.obtainStyledAttributes(attrs, R.styleable.VPBanner) this.mLoopDuration = typedArray.getInt( R.styleable.VPBanner_vp_loop_duration, DEFAULT_LOOP_DURATION ).toLong() this.mAutoLoop = typedArray.getBoolean(R.styleable.VPBanner_vp_auto_loop, false) this.mLoopOrientation = typedArray.getInt(R.styleable.VPBanner_vp_loop_orientation, LoopOrientation.LTR) Log.d("VPBanner","ld:${this.mLoopDuration},al:$mAutoLoop,lo:$mLoopOrientation") typedArray?.recycle() }
实现生命周期感知
class VPBanner : ViewPager, DefaultLifecycleObserver { override fun onResume(owner: LifecycleOwner) { Log.d(TAG, "onResume") if (this.mAutoLoop) { startLoop() } } override fun onPause(owner: LifecycleOwner) { Log.d(TAG, "onResume") stopLoop() } }
重写onTouchEvent方法
override fun onTouchEvent(ev: MotionEvent?): Boolean { when (ev?.action) { MotionEvent.ACTION_DOWN -> stopLoop() MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { prepareLoop() } } return super.onTouchEvent(ev) } private fun prepareLoop() { if (this.mAutoLoop && this.mResumed) { startLoop() } }