Android Banner - ViewPager 02
現在來給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()
}
}