Skip to content

Commit e7f9f63

Browse files
imhappikendrickumstattd
authored andcommitted
[BottomSheetDialog] Add support for androidx.core ProtectionLayout API and update dependency to 1.16
PiperOrigin-RevId: 764887825
1 parent fa0e908 commit e7f9f63

File tree

8 files changed

+127
-46
lines changed

8 files changed

+127
-46
lines changed

catalog/java/io/material/catalog/bottomsheet/BottomSheetMainDemoFragment.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import io.material.catalog.R;
2020

21+
import static com.google.android.material.bottomsheet.BottomSheetBehavior.getDefaultBottomGradientProtection;
22+
2123
import android.app.Activity;
2224
import android.os.Bundle;
2325
import android.util.DisplayMetrics;
@@ -35,12 +37,14 @@
3537
import androidx.annotation.Nullable;
3638
import androidx.core.view.ViewCompat;
3739
import androidx.core.view.WindowInsetsCompat;
40+
import androidx.core.view.insets.ProtectionLayout;
3841
import com.google.android.material.bottomsheet.BottomSheetBehavior;
3942
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback;
4043
import com.google.android.material.bottomsheet.BottomSheetDialog;
4144
import com.google.android.material.materialswitch.MaterialSwitch;
4245
import io.material.catalog.feature.DemoFragment;
4346
import io.material.catalog.windowpreferences.WindowPreferencesManager;
47+
import java.util.Collections;
4448

4549
/** A fragment that displays the main BottomSheet demo for the Catalog app. */
4650
public class BottomSheetMainDemoFragment extends DemoFragment {
@@ -100,6 +104,9 @@ public View onCreateDemoView(
100104
bottomSheetDialog.setDismissWithAnimation(true);
101105
windowPreferencesManager.applyEdgeToEdgePreference(bottomSheetDialog.getWindow());
102106
View bottomSheetInternal = bottomSheetDialog.findViewById(com.google.android.material.R.id.design_bottom_sheet);
107+
bottomSheetDialog.setProtections(
108+
Collections.singletonList(
109+
getDefaultBottomGradientProtection(getContext())));
103110
BottomSheetBehavior.from(bottomSheetInternal).setPeekHeight(peekHeightPx);
104111
View button = view.findViewById(R.id.bottomsheet_button);
105112
button.setOnClickListener(
@@ -150,6 +157,7 @@ public View onCreateDemoView(
150157
.addBottomSheetCallback(createBottomSheetCallback(dialogText));
151158
TextView bottomSheetText = view.findViewById(R.id.cat_persistent_bottomsheet_state);
152159
View bottomSheetPersistent = view.findViewById(R.id.bottom_drawer);
160+
ProtectionLayout protectionLayout = view.findViewById(R.id.cat_bottomsheet_protection_layout);
153161
persistentBottomSheetBehavior = BottomSheetBehavior.from(bottomSheetPersistent);
154162
persistentBottomSheetBehavior.addBottomSheetCallback(
155163
createBottomSheetCallback(bottomSheetText));
@@ -158,6 +166,10 @@ public View onCreateDemoView(
158166
int state = persistentBottomSheetBehavior.getState();
159167
updateStateTextView(bottomSheetPersistent, bottomSheetText, state);
160168
updateBackHandlingEnabled(state);
169+
protectionLayout.setProtections(
170+
Collections.singletonList(
171+
getDefaultBottomGradientProtection(
172+
requireContext())));
161173
});
162174
setupBackHandling(persistentBottomSheetBehavior);
163175

catalog/java/io/material/catalog/bottomsheet/BottomSheetScrollableContentDemoFragment.java

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import io.material.catalog.R;
2020

21+
import static com.google.android.material.bottomsheet.BottomSheetBehavior.getDefaultBottomGradientProtection;
22+
2123
import android.app.Dialog;
2224
import android.os.Bundle;
2325
import android.view.LayoutInflater;
@@ -33,6 +35,7 @@
3335
import com.google.android.material.internal.ViewUtils;
3436
import io.material.catalog.feature.DemoFragment;
3537
import io.material.catalog.windowpreferences.WindowPreferencesManager;
38+
import java.util.Collections;
3639

3740
/**
3841
* A fragment that displays the a BottomSheet demo with vertical scrollable content for the Catalog
@@ -64,25 +67,33 @@ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
6467
BottomSheetDialog bottomSheetDialog =
6568
new BottomSheetDialog(
6669
getContext(), R.style.ThemeOverlay_Catalog_BottomSheetDialog_Scrollable);
67-
new WindowPreferencesManager(requireContext()).applyEdgeToEdgePreference(bottomSheetDialog.getWindow());
70+
new WindowPreferencesManager(requireContext())
71+
.applyEdgeToEdgePreference(bottomSheetDialog.getWindow());
6872
View content =
6973
LayoutInflater.from(getContext())
7074
.inflate(R.layout.cat_bottomsheet_scrollable_content, new FrameLayout(getContext()));
7175
bottomSheetDialog.setContentView(content);
7276
bottomSheetDialog.getBehavior().setPeekHeight(400);
7377

7478
View bottomSheetContent = content.findViewById(R.id.bottom_drawer_2);
75-
ViewUtils.doOnApplyWindowInsets(bottomSheetContent, (v, insets, initialPadding) -> {
76-
// Add the inset in the inner NestedScrollView instead to make the edge-to-edge behavior
77-
// consistent - i.e., the extra padding will only show at the bottom of all content, i.e.,
78-
// only when you can no longer scroll down to show more content.
79-
bottomSheetContent.setPaddingRelative(
80-
initialPadding.start,
81-
initialPadding.top,
82-
initialPadding.end,
83-
initialPadding.bottom + insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom);
84-
return insets;
85-
});
79+
ViewUtils.doOnApplyWindowInsets(
80+
bottomSheetContent,
81+
(v, insets, initialPadding) -> {
82+
// Add the inset in the inner NestedScrollView instead to make the edge-to-edge behavior
83+
// consistent - i.e., the extra padding will only show at the bottom of all content,
84+
// i.e.,
85+
// only when you can no longer scroll down to show more content.
86+
bottomSheetContent.setPaddingRelative(
87+
initialPadding.start,
88+
initialPadding.top,
89+
initialPadding.end,
90+
initialPadding.bottom
91+
+ insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom);
92+
return insets;
93+
});
94+
bottomSheetDialog.setProtections(
95+
Collections.singletonList(
96+
getDefaultBottomGradientProtection(requireContext())));
8697
return bottomSheetDialog;
8798
}
8899
}

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

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,46 +14,51 @@
1414
See the License for the specific language governing permissions and
1515
limitations under the License.
1616
-->
17-
<androidx.coordinatorlayout.widget.CoordinatorLayout
18-
xmlns:android="http://schemas.android.com/apk/res/android"
19-
android:id="@+id/cat_bottomsheet_coordinator_layout"
20-
android:layout_width="match_parent"
21-
android:layout_height="match_parent">
22-
23-
<RelativeLayout
17+
<androidx.core.view.insets.ProtectionLayout
18+
xmlns:android="http://schemas.android.com/apk/res/android"
19+
android:id="@+id/cat_bottomsheet_protection_layout"
20+
android:layout_width="match_parent"
21+
android:layout_height="match_parent">
22+
<androidx.coordinatorlayout.widget.CoordinatorLayout
23+
android:id="@+id/cat_bottomsheet_coordinator_layout"
2424
android:layout_width="match_parent"
25-
android:layout_height="match_parent"
26-
android:orientation="vertical">
27-
<Button
28-
android:id="@+id/bottomsheet_button"
29-
android:layout_width="wrap_content"
30-
android:layout_height="wrap_content"
31-
android:layout_marginTop="16dp"
32-
android:layout_centerHorizontal="true"
33-
android:text="@string/cat_bottomsheet_button_text"/>
25+
android:layout_height="match_parent">
26+
27+
<RelativeLayout
28+
android:layout_width="match_parent"
29+
android:layout_height="match_parent"
30+
android:orientation="vertical">
31+
<Button
32+
android:id="@+id/bottomsheet_button"
33+
android:layout_width="wrap_content"
34+
android:layout_height="wrap_content"
35+
android:layout_marginTop="16dp"
36+
android:layout_centerHorizontal="true"
37+
android:text="@string/cat_bottomsheet_button_text"/>
38+
<com.google.android.material.materialswitch.MaterialSwitch
39+
android:id="@+id/cat_fullscreen_switch"
40+
android:layout_width="wrap_content"
41+
android:layout_height="wrap_content"
42+
android:layout_below="@id/bottomsheet_button"
43+
android:layout_centerHorizontal="true"
44+
android:padding="16dp"
45+
android:textSize="14sp"
46+
android:textAllCaps="true"
47+
android:text="@string/cat_bottomsheet_switch_text"/>
3448
<com.google.android.material.materialswitch.MaterialSwitch
35-
android:id="@+id/cat_fullscreen_switch"
49+
android:id="@+id/cat_bottomsheet_expansion_switch"
3650
android:layout_width="wrap_content"
3751
android:layout_height="wrap_content"
38-
android:layout_below="@id/bottomsheet_button"
52+
android:layout_below="@id/cat_fullscreen_switch"
3953
android:layout_centerHorizontal="true"
4054
android:padding="16dp"
41-
android:textSize="14sp"
55+
android:text="@string/cat_bottomsheet_expansion_switch_text"
4256
android:textAllCaps="true"
43-
android:text="@string/cat_bottomsheet_switch_text"/>
44-
<com.google.android.material.materialswitch.MaterialSwitch
45-
android:id="@+id/cat_bottomsheet_expansion_switch"
46-
android:layout_width="wrap_content"
47-
android:layout_height="wrap_content"
48-
android:layout_below="@id/cat_fullscreen_switch"
49-
android:layout_centerHorizontal="true"
50-
android:padding="16dp"
51-
android:text="@string/cat_bottomsheet_expansion_switch_text"
52-
android:textAllCaps="true"
53-
android:textSize="14sp"/>
57+
android:textSize="14sp"/>
5458

55-
</RelativeLayout>
59+
</RelativeLayout>
5660

57-
<!-- Standard bottom sheet will be added here. -->
61+
<!-- Standard bottom sheet will be added here. -->
5862

59-
</androidx.coordinatorlayout.widget.CoordinatorLayout>
63+
</androidx.coordinatorlayout.widget.CoordinatorLayout>
64+
</androidx.core.view.insets.ProtectionLayout>

docs/components/BottomSheet.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,15 @@ attribute in your theme.
595595
`BottomSheetDialog` will also add padding to the top when the bottom sheet
596596
slides under the status bar, to prevent content from being drawn underneath it.
597597

598+
`BottomSheetDialog` also supports
599+
[Protections](https://developer.android.com/reference/androidx/core/view/insets/Protection).
600+
If using
601+
[Gradient Protections](https://developer.android.com/reference/androidx/core/view/insets/GradientProtection),
602+
`BottomSheetBehavior` provides a `getDefaultBottomGradientProtection()` method
603+
that will return a bottom `GradientProtection` that is the color
604+
`?attr/colorSurfaceContainerLow` for Material3 or later, or `?attr/colorSurface`
605+
if otherwise not defined.
606+
598607
</details>
599608

600609
<details>

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ androidXAppCompat = "1.7.0"
1212
androidXCardView = "1.0.0"
1313
androidXConstraintLayout = "2.1.0"
1414
androidXCoordinatorLayout = "1.1.0"
15-
androidXCore = "1.6.0"
15+
androidXCore = "1.16.0"
1616
androidXComposeMaterialIconsCore = "1.7.8"
1717
androidXComposeMaterialIconsExtended = "1.7.8"
1818
androidXComposeMaterial3 = "1.4.0-alpha14"

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,15 @@
6565
import androidx.core.math.MathUtils;
6666
import androidx.core.view.ViewCompat;
6767
import androidx.core.view.WindowInsetsCompat;
68+
import androidx.core.view.WindowInsetsCompat.Side;
6869
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
6970
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
7071
import androidx.core.view.accessibility.AccessibilityViewCommand;
72+
import androidx.core.view.insets.GradientProtection;
73+
import androidx.core.view.insets.Protection;
7174
import androidx.customview.view.AbsSavedState;
7275
import androidx.customview.widget.ViewDragHelper;
76+
import com.google.android.material.color.MaterialColors;
7377
import com.google.android.material.internal.ViewUtils;
7478
import com.google.android.material.internal.ViewUtils.RelativePadding;
7579
import com.google.android.material.motion.MaterialBackHandler;
@@ -2470,4 +2474,21 @@ public boolean perform(@NonNull View view, @Nullable CommandArguments arguments)
24702474
}
24712475
};
24722476
}
2477+
2478+
/**
2479+
* Returns a default {@link GradientProtection} for use with BottomSheets.
2480+
*
2481+
* @throws IllegalArgumentException if {@code R.attr.colorSurfaceContainerLow} and {@code
2482+
* R.attr.colorSurface} are not set in the current theme.
2483+
*/
2484+
@NonNull
2485+
public static Protection getDefaultBottomGradientProtection(@NonNull Context context) {
2486+
Integer color = MaterialColors.getColorOrNull(context, R.attr.colorSurfaceContainerLow);
2487+
if (color == null) {
2488+
color =
2489+
MaterialColors.getColor(
2490+
context, R.attr.colorSurface, BottomSheetBehavior.class.getSimpleName());
2491+
}
2492+
return new GradientProtection(Side.BOTTOM, color);
2493+
}
24732494
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,13 @@
4848
import androidx.core.view.WindowInsetsCompat;
4949
import androidx.core.view.WindowInsetsControllerCompat;
5050
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
51+
import androidx.core.view.insets.Protection;
52+
import androidx.core.view.insets.ProtectionLayout;
5153
import com.google.android.material.internal.EdgeToEdgeUtils;
5254
import com.google.android.material.internal.ViewUtils;
5355
import com.google.android.material.motion.MaterialBackOrchestrator;
5456
import com.google.android.material.shape.MaterialShapeDrawable;
57+
import java.util.List;
5558

5659
/**
5760
* Base class for {@link android.app.Dialog}s styled as a bottom sheet.
@@ -79,6 +82,8 @@ public class BottomSheetDialog extends AppCompatDialog {
7982
private CoordinatorLayout coordinator;
8083
private FrameLayout bottomSheet;
8184

85+
private ProtectionLayout protectionLayout;
86+
8287
boolean dismissWithAnimation;
8388

8489
boolean cancelable = true;
@@ -279,11 +284,23 @@ public boolean getEdgeToEdgeEnabled() {
279284
return edgeToEdgeEnabled;
280285
}
281286

287+
/**
288+
* Set the {@link Protection}s applied to this BottomSheetDialog.
289+
*
290+
* @param protections the list of {@link Protection}s to apply. This value will override the
291+
* existing Protections. An empty list will clear the Protections.
292+
*/
293+
public void setProtections(@NonNull List<Protection> protections) {
294+
protectionLayout.setProtections(protections);
295+
protectionLayout.setVisibility(protections.isEmpty() ? View.GONE : View.VISIBLE);
296+
}
297+
282298
/** Creates the container layout which must exist to find the behavior */
283299
private FrameLayout ensureContainerAndBehavior() {
284300
if (container == null) {
285301
container =
286302
(FrameLayout) View.inflate(getContext(), R.layout.design_bottom_sheet_dialog, null);
303+
protectionLayout = (ProtectionLayout) container.findViewById(R.id.protection_layout);
287304

288305
coordinator = (CoordinatorLayout) container.findViewById(R.id.coordinator);
289306
bottomSheet = (FrameLayout) container.findViewById(R.id.design_bottom_sheet);

lib/java/com/google/android/material/bottomsheet/res/layout/design_bottom_sheet_dialog.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,10 @@
4848

4949
</androidx.coordinatorlayout.widget.CoordinatorLayout>
5050

51+
<androidx.core.view.insets.ProtectionLayout
52+
android:id="@+id/protection_layout"
53+
android:layout_width="match_parent"
54+
android:layout_height="match_parent"
55+
android:visibility="gone" />
56+
5157
</FrameLayout>

0 commit comments

Comments
 (0)