-
-
Save eclectice/57645465cb8cc8a318f2048d91d01fb7 to your computer and use it in GitHub Desktop.
BottomSheetScrollView for when you have a ViewPager with RecyclerViews in your BottomSheet
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class BottomSheetScrollView(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs), | |
NestedScrollingParent2 { | |
private val TAG = "NestedScroll3" | |
private val childHelper = NestedScrollingChildHelper(this).apply { | |
isNestedScrollingEnabled = true | |
} | |
private var behavior: BottomSheetBehavior<*>? = null | |
var started = false | |
var canScroll = false | |
var pendingCanScroll = false | |
var dyPreScroll = 0 | |
init { | |
ViewCompat.setNestedScrollingEnabled(this, true) | |
} | |
private val bottomSheetCallback = object : BottomSheetBehavior.BottomSheetCallback() { | |
override fun onStateChanged(bottomSheet: View, newState: Int) { | |
onNextScrollStop(newState == BottomSheetBehavior.STATE_EXPANDED) | |
Log.d( | |
"BottomSheet", | |
"Can scroll CHANGED to: $canScroll, because bottom sheet state is ${ | |
getBottomSheetStateString(newState) | |
}" | |
) | |
} | |
override fun onSlide(bottomSheet: View, slideOffset: Float) = Unit | |
} | |
fun onNextScrollStop(canScroll: Boolean) { | |
pendingCanScroll = canScroll | |
} | |
override fun onStartNestedScroll(child: View, target: View, axes: Int, type: Int): Boolean { | |
// ViewPager2's RecyclerView does not participate in this nested scrolling. | |
// This allows it to show it's overscroll indicator. | |
if (target is RecyclerView) { | |
val layoutManager = target.layoutManager as LinearLayoutManager | |
if (layoutManager.orientation == LinearLayoutManager.HORIZONTAL) { | |
target.isNestedScrollingEnabled = false | |
return false | |
} | |
} | |
if (!started) { | |
Log.d(TAG, "started nested scroll from $target") | |
childHelper.startNestedScroll(axes, type) | |
started = true | |
} | |
return true | |
} | |
override fun onNestedScrollAccepted(child: View, target: View, axes: Int, type: Int) { | |
Log.d(TAG, "accepted nested scroll from $target") | |
canScroll = true | |
} | |
override fun onStopNestedScroll(target: View, type: Int) { | |
if (started) { | |
childHelper.stopNestedScroll(type) | |
started = false | |
Log.d( | |
TAG, | |
"stopped nested scroll from $target, changing canScroll from $canScroll to $pendingCanScroll" | |
) | |
canScroll = pendingCanScroll | |
} | |
} | |
override fun onNestedScroll( | |
target: View, | |
dxConsumed: Int, | |
dyConsumed: Int, | |
dxUnconsumed: Int, | |
dyUnconsumed: Int, | |
type: Int | |
) { | |
Log.d( | |
TAG, | |
"onNestedScroll: dxC: $dxConsumed, dyC: $dyConsumed, dxU: $dxUnconsumed, dyU: $dyUnconsumed" | |
) | |
if (dyUnconsumed == dyPreScroll && dyPreScroll < 0) { | |
canScroll = false | |
Log.d(TAG, "Can scroll CHANGED to: $canScroll, because scrolled to the top of the list") | |
} | |
} | |
override fun onNestedPreScroll(target: View, dx: Int, dy: Int, consumed: IntArray, type: Int) { | |
Log.d( | |
TAG, | |
"onNestedPreScroll: dx: $dx, dy: $dy, consumed: [ ${consumed.joinToString(", ")} ]" | |
) | |
if (!canScroll) { | |
childHelper.dispatchNestedPreScroll(dx, dy, consumed, null, type) | |
// Ensure all dy is consumed to prevent premature scrolling when not allowed. | |
consumed[1] = dy | |
} else { | |
dyPreScroll = dy | |
} | |
} | |
override fun onAttachedToWindow() { | |
super.onAttachedToWindow() | |
behavior = findBottomSheetBehaviorParent(parent) as BottomSheetBehavior<*>? | |
behavior?.addBottomSheetCallback(bottomSheetCallback) | |
} | |
override fun onDetachedFromWindow() { | |
super.onDetachedFromWindow() | |
behavior?.removeBottomSheetCallback(bottomSheetCallback) | |
} | |
private fun findBottomSheetBehaviorParent(parent: ViewParent?): CoordinatorLayout.Behavior<*>? { | |
if (parent !is View) { | |
throw IllegalArgumentException( | |
"None of this view's ancestors are associated with BottomSheetBehavior" | |
) | |
} | |
val layoutParams = parent.layoutParams | |
return if (layoutParams is CoordinatorLayout.LayoutParams && layoutParams.behavior != null) { | |
layoutParams.behavior | |
} else { | |
findBottomSheetBehaviorParent((parent as View).parent) | |
} | |
} | |
private fun getBottomSheetStateString(state: Int): String { | |
return when (state) { | |
1 -> "STATE_DRAGGING" | |
2 -> "STATE_SETTLING" | |
3 -> "STATE_EXPANDED" | |
4 -> "STATE_COLLAPSED" | |
5 -> "STATE_HIDDEN" | |
6 -> "STATE_HALF_EXPANDED" | |
else -> "0" | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment