material-components / material-components/material-components-android

[BottomSheetBehavior] BottomSheetBehavior doesn't play well with layout transitions

Open
#2,062 4 comments 15 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug Widget: BottomSheet
Dominant language
Java
Stars
17.4k
Forks
3.2k
PR merge metrics
No merged PRs in 30d

Description

**Description:** layout with attached BottomSheetBehavior jumps to top of its parent container if you change view visibility inside it with enabled LayoutTransitions.

Here is how it looks like with enabled layout transitions:

![with-transitions](https://user-images.githubusercontent.com/3338261/107677100-f07e9600-6caa-11eb-9ad7-31a43c940550.gif)

And if I disable layout transitions it works as expected:

![without-transitions](https://user-images.githubusercontent.com/3338261/107677150-05f3c000-6cab-11eb-9fb6-a57afabd9a5b.gif)

**Source code:** [BottomSheetBug.zip](https://github.com/material-components/material-components-android/files/5967488/BottomSheetBug.zip)

The reason is LayoutTransition basically works as follows:

1. Remember current views state
2. Wait for next layout
3. Remember new views state
4. Start animations from old state to new state

And if we look at [BottomSheetBehavior#onLayoutChild(CoordinatorLayout, V, int)](https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/bottomsheet/BottomSheetBehavior.java#L396) method we can see this:
```java
// First let the parent lay it out
parent.onLayoutChild(child, layoutDirection);
// Offset the bottom sheet
parentWidth = parent.getWidth();
parentHeight = parent.getHeight();
childHeight = child.getHeight();
fitToContentsOffset = max(0, parentHeight - childHeight);
calculateHalfExpandedOffset();
calculateCollapsedOffset();
```
The problem here - when `parent.onLayoutChild(child, layoutDirection);` is called parent `CoordinatorLayout` lays out our view on top of itself and this causes `View.OnLayoutChangeListener` inside `LayoutTransition` to trigger with new values before `BottomSheetBehavior` have chance to offset it properly.

Ideally, I would have add some method to `CoordinatorLayout` to get view bounds without layout it, use it, then offset view to proper position and call `View#layout(int, int, int, int)` at the end from `BottomSheetBehavior`.

**Android API version:** 30

**Material Library version:** 1.3.0

**Device:** API 25 emulator

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with BottomSheetBehavior#onLayoutChild(CoordinatorLayout, V, int) and reproduce the issue using the linked BottomSheetBug.zip on the described Android and Material Library versions. Trace how CoordinatorLayout layout and LayoutTransition callbacks interact before the bottom sheet is offset. Done means changing child visibility with LayoutTransitions enabled no longer makes the bottom sheet jump to the parent’s top.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, java
Domain
mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.