现在来给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()
}
}