208 lines
7.2 KiB
Kotlin
208 lines
7.2 KiB
Kotlin
package com.gh.common.view
|
|
|
|
import android.content.Context
|
|
import android.util.AttributeSet
|
|
import android.view.*
|
|
import android.widget.LinearLayout
|
|
import androidx.core.content.ContextCompat
|
|
import androidx.recyclerview.widget.RecyclerView
|
|
import androidx.viewpager2.widget.ViewPager2
|
|
import com.facebook.drawee.view.SimpleDraweeView
|
|
import com.gh.common.util.DisplayUtils
|
|
import com.gh.common.util.ImageUtils
|
|
import com.gh.common.util.rxTimer
|
|
import com.gh.gamecenter.R
|
|
import com.gh.gamecenter.entity.SettingsEntity
|
|
import io.reactivex.disposables.Disposable
|
|
import kotlin.math.abs
|
|
|
|
|
|
/**
|
|
* 视频流广告轮播控件
|
|
*/
|
|
class AdBannerView : LinearLayout {
|
|
|
|
private lateinit var mViewPager2: ViewPager2
|
|
private var mDatas = ArrayList<SettingsEntity.Advertisement>()
|
|
var isAutoPlay = true
|
|
private var currentPage = 0
|
|
private var autoDurationTime = 6000L
|
|
private var mRxTimer: Disposable? = null
|
|
private var lastX: Float = 0F
|
|
private var lastY: Float = 0F
|
|
private var startX: Float = 0F
|
|
private var startY: Float = 0F
|
|
private val mTouchSlop = ViewConfiguration.get(context).scaledTouchSlop
|
|
private val bannerWidth = DisplayUtils.dip2px(52f)
|
|
var onItemClick: ((position: Int) -> Unit)? = null
|
|
private lateinit var mIndicatorLayout: LinearLayout
|
|
|
|
constructor(context: Context) : super(context)
|
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
|
|
|
|
init {
|
|
initViews()
|
|
}
|
|
|
|
private fun initViews() {
|
|
orientation = VERTICAL
|
|
mViewPager2 = ViewPager2(context).apply {
|
|
layoutParams = ViewGroup.LayoutParams(bannerWidth, bannerWidth)
|
|
orientation = ViewPager2.ORIENTATION_HORIZONTAL
|
|
registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
|
override fun onPageSelected(position: Int) {
|
|
super.onPageSelected(position)
|
|
currentPage = position
|
|
slideIndicator(currentPage % mDatas.size)
|
|
}
|
|
})
|
|
}
|
|
val recyclerView = mViewPager2.getChildAt(0) as RecyclerView
|
|
recyclerView.overScrollMode = RecyclerView.OVER_SCROLL_NEVER
|
|
addView(mViewPager2)
|
|
mIndicatorLayout = LinearLayout(context).apply {
|
|
orientation = HORIZONTAL
|
|
gravity = Gravity.CENTER
|
|
val params = LayoutParams(LayoutParams.MATCH_PARENT, DisplayUtils.dip2px(5F))
|
|
params.topMargin = DisplayUtils.dip2px(8f)
|
|
layoutParams = params
|
|
}
|
|
addView(mIndicatorLayout)
|
|
}
|
|
|
|
|
|
fun start(datas: ArrayList<SettingsEntity.Advertisement>) {
|
|
if (datas.isNullOrEmpty()) throw IllegalArgumentException("广告列表不能为空")
|
|
val adapter = mViewPager2.adapter
|
|
mDatas = datas
|
|
if (adapter == null) {
|
|
val bannerAdapter = AdBannerAdapter()
|
|
mViewPager2.adapter = bannerAdapter
|
|
} else {
|
|
adapter.notifyDataSetChanged()
|
|
}
|
|
currentPage = (mViewPager2.adapter as AdBannerAdapter).getActualFirstPositionInCenter()
|
|
mViewPager2.setCurrentItem(currentPage, false)
|
|
if (mDatas.size > 1) {
|
|
addIndicator()
|
|
slideIndicator(currentPage % mDatas.size)
|
|
autoPlay()
|
|
}
|
|
}
|
|
|
|
private fun autoPlay() {
|
|
if (isAutoPlay && mDatas.size > 1) {
|
|
if (mRxTimer != null && !mRxTimer!!.isDisposed) {
|
|
mRxTimer?.dispose()
|
|
mRxTimer = null
|
|
}
|
|
mRxTimer = rxTimer(autoDurationTime) {
|
|
slidePage()
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private fun slidePage() {
|
|
currentPage++
|
|
mViewPager2.setCurrentItem(currentPage, true)
|
|
}
|
|
|
|
fun resumePage() {
|
|
autoPlay()
|
|
}
|
|
|
|
fun pausePage() {
|
|
if (mRxTimer != null && !mRxTimer!!.isDisposed) {
|
|
mRxTimer?.dispose()
|
|
mRxTimer = null
|
|
}
|
|
}
|
|
|
|
private fun addIndicator() {
|
|
mIndicatorLayout.removeAllViews()
|
|
mDatas.forEach { _ ->
|
|
val view = View(context).apply {
|
|
background = ContextCompat.getDrawable(context, R.drawable.selector_video_detail_ad_indicator)
|
|
val params = LayoutParams(DisplayUtils.dip2px(4F), DisplayUtils.dip2px(4F))
|
|
params.leftMargin = DisplayUtils.dip2px(2F)
|
|
params.rightMargin = DisplayUtils.dip2px(2F)
|
|
layoutParams = params
|
|
}
|
|
mIndicatorLayout.addView(view)
|
|
}
|
|
}
|
|
|
|
private fun slideIndicator(position: Int) {
|
|
for (i in 0 until mIndicatorLayout.childCount) {
|
|
val childAt = mIndicatorLayout.getChildAt(i)
|
|
childAt.isSelected = i == position
|
|
}
|
|
}
|
|
|
|
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
|
|
val action = ev.action
|
|
if (action == MotionEvent.ACTION_DOWN) {
|
|
lastX = ev.rawX
|
|
startX = lastX
|
|
lastY = ev.rawY
|
|
startY = lastY
|
|
} else if (action == MotionEvent.ACTION_MOVE) {
|
|
lastX = ev.rawX
|
|
lastY = ev.rawY
|
|
val distanceX = abs(lastX - startX)
|
|
val distanceY = abs(lastY - startY)
|
|
val disallowIntercept: Boolean
|
|
disallowIntercept = if (mViewPager2.orientation == ViewPager2.ORIENTATION_HORIZONTAL) {
|
|
distanceX > mTouchSlop && distanceX > distanceY
|
|
} else {
|
|
distanceY > mTouchSlop && distanceY > distanceX
|
|
}
|
|
parent.requestDisallowInterceptTouchEvent(disallowIntercept)
|
|
} else if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
|
|
return abs(lastX - startX) > mTouchSlop || abs(lastY - startY) > mTouchSlop
|
|
}
|
|
return super.onInterceptTouchEvent(ev)
|
|
}
|
|
|
|
override fun onDetachedFromWindow() {
|
|
super.onDetachedFromWindow()
|
|
if (mRxTimer != null && !mRxTimer!!.isDisposed) {
|
|
mRxTimer?.dispose()
|
|
mRxTimer = null
|
|
}
|
|
}
|
|
|
|
fun getAdDatas(): ArrayList<SettingsEntity.Advertisement> {
|
|
return mDatas
|
|
}
|
|
|
|
|
|
private inner class AdBannerAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
|
return object : RecyclerView.ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_ad_banner, parent, false)) {}
|
|
}
|
|
|
|
override fun getItemCount(): Int = if (mDatas.size == 1) mDatas.size else Int.MAX_VALUE
|
|
|
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
|
val ad = mDatas[position % mDatas.size]
|
|
val view = holder.itemView as SimpleDraweeView
|
|
ImageUtils.display(view,ad.image)
|
|
holder.itemView.setOnClickListener {
|
|
onItemClick?.invoke(position % mDatas.size)
|
|
}
|
|
}
|
|
|
|
fun getActualFirstPositionInCenter(): Int {
|
|
if (mDatas.size == 1) return 0
|
|
var index = itemCount / 2
|
|
if (index % mDatas.size != 0) {
|
|
index -= (index % mDatas.size)
|
|
}
|
|
return index - 1
|
|
}
|
|
}
|
|
|
|
} |