diff --git a/README.md b/README.md index 909404b..811060d 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,31 @@ 4. 项目无偿使用,请注明出处和作者信息 +### USE by Kotlin + implementation 'com.uis:adsorbent:0.1.3 + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "com.android.support:recyclerview-v7:$supportVer" + + +``` 项目中使用的是compileOnly,使用者需自行加入外部依赖库 ``` + +### VERSION + +Version|Descipt|Fixed|Time +----|----|----|---- +0.1.1|初始版本| |2019/05/23 +0.1.2|新增|快速滑动联动效果| |2019/05/24 +0.1.3|更改|快速滑动联动处理| |2019/05/25 ### USE +##### 事件分发ParentRecyclerView设置 + /** true 开启滑动冲突处理(默认true)*/ + recyclerView.enableConflict = true + /** 开启快速滚动parent带动child联动效果(默认false)*/ + recyclerView.enableParentChain = false + /** 开启快速滚动child带动parent联动效果(默认true)*/ + recyclerView.enableChildChain = true + ##### Single recyclerView.addOnScrollListener(object : SingleAdsorbentListener(){ /** 获取被吸顶ViewGroup*/ @@ -72,23 +95,6 @@ container.addView(view) return view } - - -### USE by Kotlin - implementation 'com.uis:adsorbent:0.1.2 - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "com.android.support:recyclerview-v7:$supportVer" - - -``` 项目中使用的是compileOnly,使用者需自行加入外部依赖库 ``` - -### VERSION - -Version|Descipt|Fixed|Time -----|----|----|---- -0.1.1|初始版本| |2019/05/23 -0.1.2|fixed快速滑动联动效果| |2019/05/24 - ### LICENSE MIT License diff --git a/adsorbent/build.gradle b/adsorbent/build.gradle index 0e53b10..61bbaeb 100644 --- a/adsorbent/build.gradle +++ b/adsorbent/build.gradle @@ -1,6 +1,5 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' android { compileSdkVersion compileVer diff --git a/adsorbent/src/main/java/com/uis/adsorbent/ChildRecyclerView.kt b/adsorbent/src/main/java/com/uis/adsorbent/ChildRecyclerView.kt index d95202f..f2dc868 100644 --- a/adsorbent/src/main/java/com/uis/adsorbent/ChildRecyclerView.kt +++ b/adsorbent/src/main/java/com/uis/adsorbent/ChildRecyclerView.kt @@ -20,43 +20,29 @@ class ChildRecyclerView :RecyclerView{ /** true 开启滑动冲突处理*/ var enableConflict = true - /** 抬手动作记录滚动状态*/ - private var actionUpState = SCROLL_STATE_IDLE /** 记录上次的parent,避免递归频繁*/ private var parentView :WeakReference? = null init { addOnScrollListener(object :OnScrollListener(){ override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { - //Log.e("xx","child statechanged $newState, isTop="+!canScrollVertically(-1)) /** 滚动停止且到了顶部,快速滑动事件往上给parent view*/ - if(SCROLL_STATE_IDLE == newState && !canScrollVertically(-1) && SCROLL_STATE_DRAGGING == actionUpState){ - parentView?.get()?.let { - it.onScrollChain() - } + if(SCROLL_STATE_IDLE == newState && !canScrollVertically(-1)){ + parentView?.get()?.onScrollChain() } } }) } override fun dispatchTouchEvent(ev: MotionEvent): Boolean { - /** true child在顶部*/ if(enableConflict) { induceParentOfChildTopStatus() - when(ev.action){ - MotionEvent.ACTION_DOWN ->{ - actionUpState = SCROLL_STATE_IDLE - } - MotionEvent.ACTION_UP -> { - actionUpState = scrollState - } - } } - //Log.e("xx","child action ${ev.action} state $scrollState,y= ${ev.y}") return super.dispatchTouchEvent(ev) } private fun induceParentOfChildTopStatus(){ + /** true child在顶部*/ val isChildTop = !canScrollVertically(-1) parentView?.get()?.let { it.onTopChild(isChildTop) diff --git a/adsorbent/src/main/java/com/uis/adsorbent/ParentRecyclerView.kt b/adsorbent/src/main/java/com/uis/adsorbent/ParentRecyclerView.kt index abd7d6c..208a395 100644 --- a/adsorbent/src/main/java/com/uis/adsorbent/ParentRecyclerView.kt +++ b/adsorbent/src/main/java/com/uis/adsorbent/ParentRecyclerView.kt @@ -13,6 +13,7 @@ import android.support.v7.widget.RecyclerView import android.util.AttributeSet import android.util.Log import android.view.MotionEvent +import android.view.VelocityTracker class ParentRecyclerView :RecyclerView, OnInterceptListener { constructor(context: Context) : super(context) @@ -22,62 +23,55 @@ class ParentRecyclerView :RecyclerView, OnInterceptListener { private var isChildTop = true private var startdy = 0f private var startdx = 0f - private var lastdy = 0f - private var enddy = 0f - private var lastTouchTime = 0L private var needDispatchChild = true private var needDispatchSelf = true - private var scrollValue = ArrayList(12) - /** 是否从吸顶后开始滑动*/ private var isStartSelfBottom = false - /** 抬手动作记录滚动状态*/ - private var actionUpState = SCROLL_STATE_IDLE + private var velocity :VelocityTracker? = null + private var verticalSpeed = 0f /** true 开启滑动冲突处理*/ var enableConflict = true + /** 开启快速滚动parent带动child联动效果(默认false)*/ + var enableParentChain = false /** 开启快速滚动child带动parent联动效果*/ - var enableScrollChain = true + var enableChildChain = true init { /** parent带动child联动,此处违背吸顶原则*/ -// addOnScrollListener(object :OnScrollListener(){ -// override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { -// Log.e("xx","parent statechanged $newState, isBottom="+!canScrollVertically(1)) -// /** 滚动停止且到了底部,快速滑动事件下发给childview*/ -// if(enableScrollChain && SCROLL_STATE_IDLE == newState && !canScrollVertically(1) -// && SCROLL_STATE_DRAGGING == actionUpState && scrollValue.size > 2){ -// val manager = layoutManager -// if(manager is LinearLayoutManager){ -// var realValue = 0f -// for(v in scrollValue){ -// realValue += v -// dispatchChildTouch(manager,obtainMoveEvent(startdx,realValue)) -// } -// dispatchChildTouch(manager,obtainUpEvent(startdx,realValue)) -// } -// scrollValue.clear() -// } -// } -// }) + addOnScrollListener(object :OnScrollListener(){ + override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { + /** 滚动停止且到了底部,快速滑动事件下发给childview*/ + if(enableParentChain && SCROLL_STATE_IDLE == newState && !canScrollVertically(1) + && Math.abs(verticalSpeed) >= maxFlingVelocity/2){ + val manager = layoutManager + if(manager is LinearLayoutManager){ + val speed = Math.signum(verticalSpeed)*200 + var dy = 2000f + for(i in 0 until 4){ + dispatchChildTouch(manager,obtainMoveEvent(startdx,dy)) + dy += speed + } + dispatchChildTouch(manager,obtainUpEvent(startdx,dy)) + } + } + } + }) } override fun onTopChild(isTop: Boolean) { isChildTop = isTop - //Log.e("xx","onTopChild $isTop") } override fun onScrollChain() { - actionUpState = 0 - if(enableScrollChain && !canScrollVertically(1) && scrollValue.size > 2) { - //Log.e("xx", "parent onScrollChain...") - var realValue = 0f - for (v in scrollValue) { - realValue += v - dispatchSelfTouch(obtainMoveEvent(startdx, realValue)) + if(enableChildChain && isStartSelfBottom && Math.abs(verticalSpeed) >= maxFlingVelocity) { + val speed = Math.signum(verticalSpeed)*200 + var dy = 1000f + for(i in 0 until 4){ + dispatchSelfTouch(obtainMoveEvent(startdx, dy)) + dy += speed } - dispatchSelfTouch(obtainUpEvent(startdx, realValue)) - scrollValue.clear() + dispatchSelfTouch(obtainUpEvent(startdx, dy)) } } @@ -86,7 +80,10 @@ class ParentRecyclerView :RecyclerView, OnInterceptListener { } private fun dispatchConflictTouchEvent(ev: MotionEvent):Boolean{ - val now = SystemClock.currentThreadTimeMillis() + if(velocity == null){ + velocity = VelocityTracker.obtain() + } + velocity?.addMovement(ev) when(ev.action){ MotionEvent.ACTION_DOWN ->{ startdx = ev.x @@ -95,24 +92,22 @@ class ParentRecyclerView :RecyclerView, OnInterceptListener { needDispatchChild = true needDispatchSelf = true isStartSelfBottom = !canScrollVertically(1) - scrollValue.clear() - scrollValue.add(startdy) + verticalSpeed = 0f } MotionEvent.ACTION_MOVE ->{ - scrollValue.add( (ev.y-lastdy)/(now-lastTouchTime)) if(conflictMoveEvent(ev)){ - lastdy = ev.y - lastTouchTime = now return true } } MotionEvent.ACTION_UP ->{ - actionUpState = scrollState - enddy = (ev.y-lastdy)/(now-lastTouchTime) + velocity?.let { + it.computeCurrentVelocity(1000, maxFlingVelocity.toFloat()) + verticalSpeed = it.getYVelocity() + } + velocity?.recycle() + velocity = null } } - lastdy = ev.y - lastTouchTime = now //Log.e("xx","parent action= ${ev.action} ,state= $scrollState ,y= ${ev.y}, isBotton="+!canScrollVertically(1)) return false } @@ -164,6 +159,7 @@ class ParentRecyclerView :RecyclerView, OnInterceptListener { if(needDispatchSelf) { needDispatchSelf = false onTouchEvent(obtainDownEvent(ev.x, ev.y)) + SystemClock.sleep(2) } onTouchEvent(ev) } @@ -176,6 +172,7 @@ class ParentRecyclerView :RecyclerView, OnInterceptListener { if (needDispatchChild) { needDispatchChild = false it.dispatchTouchEvent(obtainDownEvent(ev.x, ev.y)) + SystemClock.sleep(2) } it.dispatchTouchEvent(ev) }