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
- Describes several states of BottomSheetBehavior
- Describes event distribution of BottomSheetBehavior
- How does BottomSheetBehavior handle nested sliding
- 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
- STATE_EXPANDED All expansion status
- STATE_COLLAPSED state
- STATE_DRAGGING state
- STATE_SETTLING
- STATE_HIDDEN Hidden state
- STATE_HALF_EXPANDED Semi-expanded state
In what way does the system implement the different offsets for each state?
- Layout stage by ViewCompat. OffsetTopAndBottom (child, offset) to achieve the offset
- 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
- Height is -1, peekHeightAuto is set to true.
- 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
- Source code analysis
- Scene change
- 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
- 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
- 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