1. The introduction

BottomSheetBehavior can achieve what effect, a picture is worth a thousand words.

If it’s just dragging up and down and hiding. It is not difficult to put aside the BottomSheetBehavior to achieve their own, in the era of no CoordinatorLayout, this effect is often handmade. So why did Google specifically design BottomSheetBehavior? To figure this out, I dug into the source code and did find some hidden corners. I will explain the design idea of BottomSheetBehavior from the following aspects

  1. Describes several states of BottomSheetBehavior
  2. Describes event distribution of BottomSheetBehavior
  3. How does BottomSheetBehavior handle nested sliding
  4. To achieve the effect of amap home page, welcome to pay attention to the wechat public number of byte station

2. Several states of BottomSheetBehavior

There are six states in BottomSheetBehavior

  1. STATE_EXPANDED All expansion status
  2. STATE_COLLAPSED state
  3. STATE_DRAGGING state
  4. STATE_SETTLING
  5. STATE_HIDDEN Hidden state
  6. STATE_HALF_EXPANDED Semi-expanded state

In what way does the system implement the different offsets for each state?

  1. Layout stage by ViewCompat. OffsetTopAndBottom (child, offset) to achieve the offset
  2. In the user touch interaction phase, the offset is realized by viewDragHelper. dragTo(left,top,dx,dy)

2.1 Layout stage

The Layout phase ends with the findScrollingChild method to find descendant Views that have nested sliding enabled. In fact, this is the main consideration for Google to independently develop BottomSheetBehavior. Satisfies the BottomSheet effect that supports nested sliding.

2.2 User touch interaction stage

2.3 Status Offset

state The offset
STATE_COLLAPSED collapsedOffset
STATE_EXPANDED getExpandedOffset()
STATE_HALF_EXPANDED halfExpandedOffset
STATE_HIDDEN parentHeight

1. Calculate collapsedOffset

The variable name The default value
PEEK_HEIGHT_AUTO Constant value 1
peekHeightMin The default value is 64DP and cannot be changed
peekHeightAuto The default value is true, which is configurable
peekHeight The default is 0, if PEEK_HEIGHT_AUTO peekHeightAuto is true, otherwise false, and 0 if less than -1
fitToContents The default value is true, which is configurable
fitToContentOffset   Math.max(0, parentHeight – child.getHeight())

PeekHeight The default value is 0. The setup logic is as follows

  1. Height is -1, peekHeightAuto is set to true.
  2. Otherwise, peekHeightAuto is false, and peekHeight is a minimum of 0.

There are four cases in which the collapsedOffset value is calculated

Case peekHeightAuto fitToContents
case1 true true
case2 true false
case3 false true
case4 false false

The return value

Case The return value
Case1 Math.max(parentHeight – Math.max(peekHeightMin, parentHeight – parentWidth * 9 / 16), fitToContentsOffset)
Case2 parentHeight-Math.max(peekHeightMin, parentHeight – parentWidth * 9 / 16)
Case3 Math.max(parentHeight – peekHeight, fitToContentsOffset)
Case4 parentHeight – peekHeight

2. Calculate halfExpandedOffset

3. Calculate expandedOffset

4. How to fix the height of BottomSheetBehavior?

Understand the benefits of calculating these values. So let’s say I want the BottomSheetBehavior, fixed height, not to slide up and not to slide down. CollapsedOffset and expandedOffset need to be the same as collapsedOffset.

The following code

For a good reading experience there is no block rendering of the code, if you want to get the code please visit the Github codebase

3. Explain event distribution of BottomSheetBehavior

There is a way to learn about Android event distribution. I summed it up as “Three axe” analysis

  1. Source code analysis
  2. Scene change
  3. Tree diagram analysis

3.1 Sanbanax source analysis

From onInterceptTouchEvent code, can see viewDragHelper shouldInterceptTouchEvent (event), the method makes viewDragHelper intercept method.

The initialization of ViewDragHelper passes in the viewDragHelper. Callback dragCallback object, The object of Boolean tryCaptureView (View child, int pointerId) method determine viewDragHelper. ShouldInterceptTouchEvent return values.

The onInterceptTouchEvent intercepting logic is as follows

OnTouchEvent is handled primarily by ViewDragHelper#processTouchEvent. If it is a Move event, it will eventually call the dragTo method to Move

3.2 Scene and tree diagram analysis of The Three banbanax

In the following scenario, the user can swipe up and down in the Areas of HeadLayout, NestedScrollingChild, and TopMostLayout. In these three cases, what is the event processing path?

The tree is transformed as follows

Set the BottomSheetBehavior to the Behavior of the LinearLayout

3.2.1. Slide up and down in the HeadLayout area

  1. The Down event handling, the initial state, will not call tryCaptureViewForDrag method in ViewDragHelper shouldInterceptTouchEvent method, this method returns false. In BottomSheetBehavior onInterceptTouchEvent, the complete event path is as follows, and the red line represents the event distribution path

Combined with tree analysis. Because BottomSheetBehavior does not intercept events. The Down event distribution process is as follows

You end up calling the onTouchEvent method at BottomSheetBehavior, and you end up calling the processTouchEvent method at ViewDragHelper

The dragState of ViewDragHelper will eventually be set to STATE_DRAGGING

  1. The MOVE event is distributed in BottomSheetBehavior onInterceptTouchEvent as follows

Next, call the onTouchEvent method of the BottomSheetBehavior directly. The processTouchEvent method of ViewDragHelper is also called

3.2.2. Slide up and down in the NestedScrollingView area

1. Distribute the Down event to the onInterceptTouchEvent of BottomSheetBehavior. The distribution process is as follows

Due to non-interception. The Down event is distributed to the NestedScrollingChild, which initiates the nested slide and works with the BottomSheetBehavior to complete the nested slide

2. The Move event distribution process is complicated. When the Move distance in THE NSC does not reach the threshold, the Move will continue to be distributed to the onInterceptTouchEvent of BottomSheetBehavior. Will call the parent. RequestDisallowInterceptTouchEvent (true) from now on to the NSC, is purely a nested sliding.

Then the event is distributed to NSC. When the MOVE distance is greater than the threshold, the event is directly processed by NSC.

3.2.3. Slide up and down in the TopMostLayout area, which has no intersection with the NSC area

The Down event is the same as the preceding

MOVE event when distance >ViewDragHelper threshold

Since the MOVE event is intercepted, it will be handled by the BottomSheetBehavior onTouchEvent, as shown below

End of 4.

This is basically the end of the event distribution mechanism for BottomSheetBehavior. The details are not perfect. Paper come zhongjue shallow, I hope readers can combine the article to explore the source code. Next time I will use BottomSheetBehavior to achieve the home page effect of amap. Welcome to continue to follow

My open source project

I open source a convenient RecyclerView top top Android library, welcome you to visit github.com/lizijin/Sti… , if you use this library, please give your valuable comments.

It currently supports the following features:

  • Support complex top View function
  • Support multiple types of top suction function
  • Enable or disable the top suction function
  • Supports setting top offset
  • Supports ItemDecoration and ItemAnimator
  • Support RecyclerView data changes and scrolling to the specified location
  • More features