AnimateLayoutChanges = "true" in a BottomSheetView showing unexpected behavior

I have a BottomSheetView that has animateLayoutChanges="true" . Initially, this manifests itself well. But if you change the visibility view (inside BottomSheetView ) from GONE to VISIBLE , the application will BottomSheetView up the calculations, and my BottomSheetView move to the top of the screen. I tried setting layout_gravity=bottom to the root of the BottomSheetView layout. But no success.

Here I have an image of my BottomSheetView , before changing the visibility of any kind. (Click image for a larger view)

enter image description here

After changing the view visibility ( GONE to VISIBLE or VISIBLE to GONE ) my BottomSheetView file moves up. (Click image for a larger view)

enter image description here

I assume Android is messing around doing calculations about measuring the width and height kind. Any way to solve this problem?

I also tried to fully expand my BottomSheetView to fit the parent view, but somehow this makes the height of BottomSheetView longer than the phone screen and in the scroll creation settings.

Expected Resolutions:

1> Prevent BottomSheetView changing its position even when the visibility view changes.

OR

2> Match the parent element of the BottomSheetView so that it does not look bad after it BottomSheetView up the calculations.

+15
source share
4 answers

I ran into the same problem and decided to find a fix. I was able to find the root cause, but, unfortunately, right now I do not see a big fix.

Cause: A problem occurs between the behavior of the bottom sheet and LayoutTransition. When a LayoutTransition is created, it creates an OnLayoutChangeListener in the view so that it can capture its endValues ​​and customize the animator with the appropriate values. This OnLayoutChangeListener is launched in a call to bottomSheetBehavior onLayout() when it first calls parent.onLayout(child) . The parent will mock the child, as usual, ignoring any biases that the behavior will change later. The problem is here. View values ​​at this point are captured by the OnLayoutChangeListener function and stored in the animator. When an animation starts, it will animate these values, not where your behavior determines it. Unfortunately, the LayoutTransition class does not give us access to animators, allowing us to update the final values.

Bugfix: Currently, I do not see an elegant solution that includes LayoutTransitions. I am going to provide an error for accessing and updating LayoutTransition animators. At this point, you can disable any layoutTransition in the parent container using layoutTransition.setAnimateParentHierachy(false) . Then you can animate the change yourself. I can update my answer with a working example as soon as I can.

+7
source

Currently BottomSheetBehavior does not work with LayoutTransition ( animateLayoutChanges="true" ). I will work on a fix.

At the moment, you can use instead of Transition . Something like this will disappear from the inside and animate the size of the bottom sheet.

 ViewGroup bottomSheet = ...; View hidingView = ...; TransitionManager.beginDelayedTransition(bottomSheet); hidingView.setVisibility(View.GONE); 

You can refer to the "Apply Transition" section for more information, including how to customize the animation.

+7
source

In the default layout, the BottomSheetDialog ( design_bottom_sheet_dialog ) has TOP gravity in the design_bottom_sheet FrameLayout dialog:

  android:layout_gravity="center_horizontal|top" 

I really don't know why gravity is the best on the Bottom SheetDialog.

You need to create the same layout file (with the same contents and name) in your project and replace this line:

 android:layout_gravity="center_horizontal|bottom" 
+1
source

The question was asked more than two years ago, but, unfortunately, the problem persists.

I finally got the decision to save the addView and removeView to the BottomSheet, having animateLayoutChanges="true" .

BottomSheetBehavior cannot calculate the correct height when it changes, so the height must remain unchanged. To do this, I set the height of the BottomSheet match_parent and split it into two match_parent : the content and Space which changes the height to match the height of the content.

To best simulate the true behavior of BottomSheet , you also need to add a TouchToDismiss view that darkens the background when expanding the BottomSheet and also close the BottomSheet when the user clicks outside the content.

Here is the code:

activity.xml

 <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/show_bottom_sheet" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Show bottom sheet"/> <View android:id="@+id/touch_to_dismiss" android:layout_width="match_parent" android:layout_height="match_parent" android:clickable="true" android:background="#9000"/> <LinearLayout android:id="@+id/bottom_sheet" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"> <Space android:id="@+id/space" android:layout_width="0dp" android:layout_height="0dp" android:layout_weight="1"/> <LinearLayout android:id="@+id/bottom_sheet_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:animateLayoutChanges="true"> <Button android:id="@+id/add_or_remove_another_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Add another view"/> <TextView android:id="@+id/another_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Another view"/> </LinearLayout> </LinearLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout> 

activity.java

 BottomSheetBehavior bottomSheetBehavior; View touchToDismiss; LinearLayout bottomSheet; Button showBottomSheet; Space space; LinearLayout bottomSheetContent; Button addOrRemoveAnotherView; TextView anotherView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); touchToDismiss = findViewById(R.id.touch_to_dismiss); touchToDismiss.setVisibility(View.GONE); touchToDismiss.setOnClickListener(this); bottomSheet = findViewById(R.id.bottom_sheet); bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet); bottomSheetBehavior.setPeekHeight(0); bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { if (newState == BottomSheetBehavior.STATE_HIDDEN || newState == BottomSheetBehavior.STATE_COLLAPSED) { touchToDismiss.setVisibility(View.GONE); }else { touchToDismiss.setVisibility(View.VISIBLE); } } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { touchToDismiss.setAlpha(getRealOffset()); } }); showBottomSheet = findViewById(R.id.show_bottom_sheet); showBottomSheet.setOnClickListener(this); space = findViewById(R.id.space); bottomSheetContent = findViewById(R.id.bottom_sheet_content); addOrRemoveAnotherView = findViewById(R.id.add_or_remove_another_view); addOrRemoveAnotherView.setOnClickListener(this); anotherView = findViewById(R.id.another_view); bottomSheetContent.removeView(anotherView); } @Override public void onClick(View v) { if (v == showBottomSheet) bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); else if (v == addOrRemoveAnotherView) { if (anotherView.getParent() == null) bottomSheetContent.addView(anotherView); else bottomSheetContent.removeView(anotherView); } else if (v == touchToDismiss) bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); } /** * Since the height does not change and remains at match_parent, it is required to calculate the true offset. * @return Real offset of the BottomSheet content. */ public float getRealOffset() { float num = (space.getHeight() + bottomSheetContent.getHeight()) - (bottomSheet.getY() + space.getHeight()); float den = bottomSheetContent.getHeight(); return (num / den); } 

This is the result obtained with this code: final result

Hope this will be helpful to someone, as the problem still exists!

0
source

Source: https://habr.com/ru/post/1263911/


All Articles