Skip to content

Commit 697d93a

Browse files
committed
[Bottom Sheet] Animate bottom sheet position when keyboard is shown using WindowInsetsAnimationCompat API
Note: android:windowSoftInputMode="adjustResize" is required in order for inset animation API to propagate the correct values, otherwise this is a no-op. This change also updates the M3 modal Bottom Sheet themes / theme overlays to use adjustResize by default (can still be overridden by the client). PiperOrigin-RevId: 508351766
1 parent c0e9f56 commit 697d93a

File tree

7 files changed

+124
-3
lines changed

7 files changed

+124
-3
lines changed

catalog/java/io/material/catalog/AndroidManifest.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535

3636
<activity
3737
android:name=".main.MainActivity"
38-
android:exported="true">
38+
android:exported="true"
39+
android:windowSoftInputMode="adjustResize">
3940
<intent-filter>
4041
<action android:name="android.intent.action.MAIN"/>
4142
<category android:name="android.intent.category.LAUNCHER"/>

catalog/java/io/material/catalog/bottomsheet/res/layout/cat_bottomsheet_content.xml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,25 @@
3535
android:layout_marginTop="16dp"
3636
android:layout_centerHorizontal="true"/>
3737

38+
<com.google.android.material.textfield.TextInputLayout
39+
android:id="@+id/bottomsheet_textinputlayout"
40+
android:layout_width="@dimen/material_textinput_default_width"
41+
android:layout_height="wrap_content"
42+
android:layout_below="@id/bottomsheet_state"
43+
android:layout_centerHorizontal="true"
44+
android:layout_margin="16dp"
45+
android:layout_gravity="center_horizontal"
46+
android:hint="@string/cat_bottomsheet_textfield_label">
47+
<com.google.android.material.textfield.TextInputEditText
48+
android:layout_width="match_parent"
49+
android:layout_height="wrap_content"/>
50+
</com.google.android.material.textfield.TextInputLayout>
51+
3852
<Button
3953
android:id="@+id/cat_bottomsheet_modal_button"
4054
android:layout_width="wrap_content"
4155
android:layout_height="wrap_content"
42-
android:layout_below="@id/bottomsheet_state"
56+
android:layout_below="@id/bottomsheet_textinputlayout"
4357
android:layout_centerHorizontal="true"
4458
android:text="@string/cat_bottomsheet_button_label_enabled"/>
4559

catalog/java/io/material/catalog/bottomsheet/res/layout/cat_bottomsheet_fragment.xml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,25 @@
9191
android:textColor="?attr/colorOnSurface"
9292
android:textSize="18sp"/>
9393

94+
<com.google.android.material.textfield.TextInputLayout
95+
android:id="@+id/cat_persistent_bottomsheet_textinputlayout"
96+
android:layout_width="@dimen/material_textinput_default_width"
97+
android:layout_height="wrap_content"
98+
android:layout_below="@id/cat_persistent_bottomsheet_state"
99+
android:layout_centerHorizontal="true"
100+
android:layout_margin="16dp"
101+
android:layout_gravity="center_horizontal"
102+
android:hint="@string/cat_bottomsheet_textfield_label">
103+
<com.google.android.material.textfield.TextInputEditText
104+
android:layout_width="match_parent"
105+
android:layout_height="wrap_content"/>
106+
</com.google.android.material.textfield.TextInputLayout>
107+
94108
<Button
95109
android:id="@+id/cat_bottomsheet_button"
96110
android:layout_width="wrap_content"
97111
android:layout_height="wrap_content"
98-
android:layout_below="@id/cat_persistent_bottomsheet_state"
112+
android:layout_below="@id/cat_persistent_bottomsheet_textinputlayout"
99113
android:layout_centerHorizontal="true"
100114
android:text="@string/cat_bottomsheet_button_label_enabled"/>
101115

catalog/java/io/material/catalog/bottomsheet/res/values/strings.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@
4444
<string name="cat_bottomsheet_persistent">
4545
Persistent Bottomsheet
4646
</string>
47+
48+
<string name="cat_bottomsheet_textfield_label"
49+
description="The label for the bottom sheet text field. [CHAR_LIMIT=100]">
50+
Label
51+
</string>
4752
<string name="cat_bottomsheet_button_label_enabled">Enabled</string>
4853
<string name="cat_bottomsheet_button_label_disabled">Disabled</string>
4954
<string name="cat_bottomsheet_button_clicked">Button clicked</string>

lib/java/com/google/android/material/bottomsheet/BottomSheetBehavior.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,7 @@ public boolean onLayoutChild(
529529
peekHeightMin =
530530
parent.getResources().getDimensionPixelSize(R.dimen.design_bottom_sheet_peek_height_min);
531531
setWindowInsetsListener(child);
532+
ViewCompat.setWindowInsetsAnimationCallback(child, new InsetsAnimationCallback(child));
532533
viewRef = new WeakReference<>(child);
533534
// Only set MaterialShapeDrawable as background if shapeTheming is enabled, otherwise will
534535
// default to android:background declared in styles or layout.
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright (C) 2023 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.android.material.bottomsheet;
18+
19+
import android.view.View;
20+
import androidx.annotation.NonNull;
21+
import androidx.core.view.WindowInsetsAnimationCompat;
22+
import androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat;
23+
import androidx.core.view.WindowInsetsCompat;
24+
import com.google.android.material.animation.AnimationUtils;
25+
import java.util.List;
26+
27+
class InsetsAnimationCallback extends WindowInsetsAnimationCompat.Callback {
28+
29+
private final View view;
30+
31+
private int startY;
32+
private int startTranslationY;
33+
34+
private final int[] tmpLocation = new int[2];
35+
36+
public InsetsAnimationCallback(View view) {
37+
super(DISPATCH_MODE_STOP);
38+
this.view = view;
39+
}
40+
41+
@Override
42+
public void onPrepare(@NonNull WindowInsetsAnimationCompat windowInsetsAnimationCompat) {
43+
view.getLocationOnScreen(tmpLocation);
44+
startY = tmpLocation[1];
45+
}
46+
47+
@NonNull
48+
@Override
49+
public BoundsCompat onStart(
50+
@NonNull WindowInsetsAnimationCompat windowInsetsAnimationCompat,
51+
@NonNull BoundsCompat boundsCompat) {
52+
view.getLocationOnScreen(tmpLocation);
53+
int endY = tmpLocation[1];
54+
startTranslationY = startY - endY;
55+
56+
// Move the view back to its original position before the insets were applied.
57+
view.setTranslationY(startTranslationY);
58+
59+
return boundsCompat;
60+
}
61+
62+
@NonNull
63+
@Override
64+
public WindowInsetsCompat onProgress(
65+
@NonNull WindowInsetsCompat insets,
66+
@NonNull List<WindowInsetsAnimationCompat> animationList) {
67+
for (WindowInsetsAnimationCompat animation : animationList) {
68+
if ((animation.getTypeMask() & WindowInsetsCompat.Type.ime()) != 0) {
69+
// Move the view to match the animated position of the keyboard.
70+
float translationY =
71+
AnimationUtils.lerp(startTranslationY, 0, animation.getInterpolatedFraction());
72+
view.setTranslationY(translationY);
73+
break;
74+
}
75+
}
76+
return insets;
77+
}
78+
79+
@Override
80+
public void onEnd(@NonNull WindowInsetsAnimationCompat windowInsetsAnimationCompat) {
81+
view.setTranslationY(0f);
82+
}
83+
}

lib/java/com/google/android/material/bottomsheet/res/values/themes_base.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,23 @@
1717
<resources>
1818
<style name="Base.V14.Theme.Material3.Light.BottomSheetDialog" parent="Theme.Material3.Light.Dialog">
1919
<item name="android:windowIsFloating">false</item>
20+
<item name="android:windowSoftInputMode">adjustResize</item>
2021
<item name="android:windowBackground">@android:color/transparent</item>
2122
<item name="android:windowAnimationStyle">@style/Animation.Material3.BottomSheetDialog</item>
2223
<item name="bottomSheetStyle">@style/Widget.Material3.BottomSheet.Modal</item>
2324
</style>
2425

2526
<style name="Base.V14.Theme.Material3.Dark.BottomSheetDialog" parent="Theme.Material3.Dark.Dialog">
2627
<item name="android:windowIsFloating">false</item>
28+
<item name="android:windowSoftInputMode">adjustResize</item>
2729
<item name="android:windowBackground">@android:color/transparent</item>
2830
<item name="android:windowAnimationStyle">@style/Animation.Material3.BottomSheetDialog</item>
2931
<item name="bottomSheetStyle">@style/Widget.Material3.BottomSheet.Modal</item>
3032
</style>
3133

3234
<style name="Base.V14.ThemeOverlay.Material3.BottomSheetDialog" parent="Base.ThemeOverlay.Material3.Dialog">
3335
<item name="android:windowIsFloating">false</item>
36+
<item name="android:windowSoftInputMode">adjustResize</item>
3437
<item name="android:windowBackground">@android:color/transparent</item>
3538
<item name="android:windowAnimationStyle">@style/Animation.Material3.BottomSheetDialog</item>
3639
<item name="bottomSheetStyle">@style/Widget.Material3.BottomSheet.Modal</item>

0 commit comments

Comments
 (0)