CoordinatorLayout+AppBarLayout+viewPager2+fragment+下拉刷新的RecyclerView
下滑
上滑
当手指下滑的时候,因为AppBarLayout还没有折叠,滑动事件会被PtrframeLayout消费,但上滑是如果AppBarLayout还没有折叠,滑动事件也会被PtrframeLayout消费但和AppBarLayout.Behavior的滑动产生冲突,会发生滑动抖动,网上说重写AppBarLayout.Behavior可以解决,或者重写PtrframeLayout,对上下滑动事件进行拦截,也可以。
这个涉及安卓事件分发机制,不会的朋友可以搜一下。
当下滑时让PtrframeLayout自行消费,上滑时进行拦截。
以上是我个人理解,有错误希望大佬指出。
上代码。
fragment_home.xml
重写PtrframeLayout
class PullRefreshLayout @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : PtrframeLayout(context, attrs, defStyleAttr), PtrUIHandler {
private val viewBinding = ViewRecyclerHeaderBinding.inflate(LayoutInflater.from(context), this, false)
private var onPullRefreshListener: OnPullRefreshListener? = null
companion object {
private const val TAG = "PullRefreshLayout"
}
init {
disableWhenHorizontalMove(true)
isKeepHeaderWhenRefresh = true
setRatioOfHeaderHeightToRefresh(1F)
headerView = viewBinding.root
addPtrUIHandler(this)
setPtrHandler(
object : PtrDefaultHandler() {
override fun onRefreshBegin(layout: PtrframeLayout) {
onPullRefreshListener?.onRefreshBegin()
}
})
}
override fun onUIReset(layout: PtrframeLayout) {
}
override fun onUIRefreshPrepare(layout: PtrframeLayout) {
Log.d(TAG, "onUIRefreshPrepare")
viewBinding.tvRefreshState.setText(R.string.refresh_pull_down_to_refresh)
}
override fun onUIRefreshBegin(layout: PtrframeLayout) {
Log.d(TAG, "onUIRefreshBegin")
viewBinding.tvRefreshState.setText(R.string.refresh_refreshing)
}
override fun onUIRefreshComplete(layout: PtrframeLayout) {
Log.d(TAG, "onUIRefreshComplete")
viewBinding.tvRefreshState.setText(R.string.refresh_refresh_complete)
}
override fun onUIPositionChange(layout: PtrframeLayout, isUnderTouch: Boolean, status: Byte, ptrIndicator: PtrIndicator) {
val offsetToRefresh: Int = layout.offsetToRefresh
val currentPos = ptrIndicator.currentPosY
val lastPos = ptrIndicator.lastPosY
if (currentPos < offsetToRefresh && lastPos >= offsetToRefresh) {
if (isUnderTouch && status == PTR_STATUS_PREPARE) {
viewBinding.tvRefreshState.setText(R.string.refresh_pull_down_to_refresh)
}
} else if (currentPos > offsetToRefresh && lastPos <= offsetToRefresh) {
if (isUnderTouch && status == PTR_STATUS_PREPARE) {
viewBinding.tvRefreshState.setText(R.string.refresh_release_to_refresh)
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
}
}
}
fun setOnPullRefreshListener(listener: OnPullRefreshListener) {
this.onPullRefreshListener = listener
}
interface onPullRefreshListener {
fun onRefreshBegin()
}
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
val x: Float = ev.getX()
val y: Float = ev.getY()
when (ev.action) {
MotionEvent.ACTION_DOWN -> {
//将按下时的坐标存储
downX = x
downY = y
}
MotionEvent.ACTION_MOVE -> {
//获取到距离差
val dx: Float = x - downX
val dy: Float = y - downY
//通过距离差判断方向
val orientation: Int = getOrientation(dx, dy)
when (orientation) {
UP ->{
return super.dispatchTouchEventSupper(ev)
}
}
}
}
return super.dispatchTouchEvent(ev)
}
override fun dispatchTouchEventSupper(ev: MotionEvent): Boolean {
val x: Float = ev.getX()
val y: Float = ev.getY()
when (ev.action) {
MotionEvent.ACTION_DOWN -> {
//将按下时的坐标存储
downX = x
downY = y
}
MotionEvent.ACTION_MOVE -> {
//获取到距离差
val dx: Float = x - downX
val dy: Float = y - downY
//通过距离差判断方向
val orientation: Int = getOrientation(dx, dy)
when (orientation) {
UP ->{
return super.dispatchTouchEventSupper(ev)
}
}
}
}
return super.dispatchTouchEventSupper(ev)
}
private var downX: Float = 0f//按下时 的X坐标
private var downY: Float = 0f//按下时 的Y坐标
private val LEFT: Int = 0
private val RIGHT: Int = 1
private val UP: Int = 2
private val DOWN: Int = 3
private fun getOrientation(dx: Float, dy: Float): Int {
return if (Math.abs(dx) > Math.abs(dy)) {
//X轴移动
if (dx > 0) RIGHT else LEFT //右,左
} else {
//Y轴移动
if (dy > 0) DOWN else UP //下//上
}
}
view_recycler_header.xml



