Skip to content

Commit 8055a2c

Browse files
afohrmandsn5ft
authored andcommitted
[Adaptive][Side Sheet] Added coplanar side sheet with APIs for setting a coplanar sibling view.
PiperOrigin-RevId: 493959543 (cherry picked from commit bc61d6d)
1 parent 0949e9c commit 8055a2c

File tree

10 files changed

+409
-9
lines changed

10 files changed

+409
-9
lines changed

catalog/java/io/material/catalog/sidesheet/SideSheetMainDemoFragment.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,19 @@ public View onCreateDemoView(
110110
modalSideSheetCloseIconButton.setOnClickListener(v -> sideSheetDialog.hide());
111111
}
112112

113+
// Set up coplanar side sheet.
114+
View coplanarSideSheet =
115+
setUpSideSheet(
116+
view,
117+
R.id.coplanar_side_sheet_container,
118+
R.id.show_coplanar_side_sheet_button,
119+
R.id.coplanar_side_sheet_close_icon_button);
120+
121+
setSideSheetCallback(
122+
coplanarSideSheet,
123+
R.id.coplanar_side_sheet_state_text,
124+
R.id.coplanar_side_sheet_slide_offset_text);
125+
113126
return view;
114127
}
115128

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?xml version="1.0" encoding="utf-8"?><!--
2+
Copyright 2022 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+
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
17+
xmlns:app="http://schemas.android.com/apk/res-auto"
18+
xmlns:tools="http://schemas.android.com/tools"
19+
android:layout_width="match_parent"
20+
android:layout_height="match_parent"
21+
android:padding="24dp"
22+
android:gravity="center_horizontal"
23+
android:orientation="vertical">
24+
25+
<Button
26+
android:id="@+id/coplanar_side_sheet_close_icon_button"
27+
style="?attr/materialIconButtonStyle"
28+
android:layout_width="wrap_content"
29+
android:layout_height="wrap_content"
30+
android:contentDescription="@string/cat_sidesheet_close_button_content_desc"
31+
app:icon="@drawable/ic_close_vd_theme_24px"
32+
app:layout_constraintEnd_toEndOf="parent"
33+
app:layout_constraintTop_toTopOf="parent"
34+
tools:ignore="ContentDescription" />
35+
36+
<TextView
37+
android:id="@+id/coplanar_side_sheet_title_text"
38+
android:layout_width="0dp"
39+
android:layout_height="wrap_content"
40+
android:text="@string/cat_sidesheet_coplanar_title"
41+
android:textAppearance="?attr/textAppearanceHeadlineSmall"
42+
app:layout_constraintEnd_toStartOf="@id/coplanar_side_sheet_close_icon_button"
43+
app:layout_constraintStart_toStartOf="parent"
44+
app:layout_constraintTop_toTopOf="parent" />
45+
46+
<androidx.core.widget.NestedScrollView
47+
android:layout_width="0dp"
48+
android:layout_height="wrap_content"
49+
app:layout_constraintEnd_toEndOf="parent"
50+
app:layout_constraintStart_toStartOf="parent"
51+
app:layout_constraintTop_toBottomOf="@id/coplanar_side_sheet_title_text">
52+
53+
<LinearLayout
54+
android:layout_width="match_parent"
55+
android:layout_height="wrap_content"
56+
android:orientation="vertical">
57+
58+
<TextView
59+
android:id="@+id/coplanar_side_sheet_state_text"
60+
android:layout_width="wrap_content"
61+
android:layout_height="wrap_content"
62+
android:text="@string/cat_sidesheet_state_settling"
63+
android:textAppearance="?attr/textAppearanceHeadlineSmall" />
64+
65+
<TextView
66+
android:id="@+id/coplanar_side_sheet_slide_offset_text"
67+
android:layout_width="wrap_content"
68+
android:layout_height="wrap_content"
69+
android:text="@string/cat_sidesheet_slide_offset_text"
70+
android:textAppearance="?attr/textAppearanceHeadlineSmall" />
71+
72+
<TextView
73+
android:layout_width="wrap_content"
74+
android:layout_height="wrap_content"
75+
android:text="@string/cat_sidesheet_filler_text" />
76+
</LinearLayout>
77+
</androidx.core.widget.NestedScrollView>
78+
</androidx.constraintlayout.widget.ConstraintLayout>

catalog/java/io/material/catalog/sidesheet/res/layout/cat_sidesheet_fragment.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@
6565
android:layout_height="wrap_content"
6666
android:layout_marginTop="16dp"
6767
android:text="@string/cat_sidesheet_modal_button_show_text" />
68+
<Button
69+
android:id="@+id/show_coplanar_side_sheet_button"
70+
android:layout_width="wrap_content"
71+
android:layout_height="wrap_content"
72+
android:layout_marginTop="16dp"
73+
android:text="@string/cat_sidesheet_coplanar_button_show_text" />
6874
<TextView
6975
android:layout_width="wrap_content"
7076
android:layout_height="wrap_content"
@@ -96,4 +102,16 @@
96102
<include layout="@layout/cat_sidesheet_content_vertically_scrolling" />
97103
</LinearLayout>
98104

105+
<LinearLayout
106+
android:id="@+id/coplanar_side_sheet_container"
107+
android:layout_width="256dp"
108+
android:layout_height="match_parent"
109+
android:layout_gravity="end"
110+
android:orientation="vertical"
111+
app:coplanarSiblingViewId="@id/nested_scroll_view"
112+
app:layout_behavior="@string/side_sheet_behavior"
113+
tools:targetApi="lollipop">
114+
<include layout="@layout/cat_sidesheet_content_coplanar" />
115+
</LinearLayout>
116+
99117
</androidx.coordinatorlayout.widget.CoordinatorLayout>

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@
6161
Show Modal Side Sheet
6262
</string>
6363

64+
<string name="cat_sidesheet_coplanar_title" description="Title of the coplanar side sheet. [CHAR_LIMIT=NONE]">
65+
Coplanar Side Sheet
66+
</string>
67+
<string name="cat_sidesheet_coplanar_button_show_text" description="Label of button which shows the modal side sheet. [CHAR_LIMIT=NONE]">
68+
Show Coplanar Side Sheet
69+
</string>
70+
6471
<string name="cat_sidesheet_close_button_content_desc" description="Content description for the button to hide the side sheet. [CHAR_LIMIT=NONE]">
6572
Close sheet button
6673
</string>

lib/java/com/google/android/material/sidesheet/RightSheetDelegate.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static java.lang.Math.max;
2222

2323
import android.view.View;
24+
import android.view.ViewGroup.MarginLayoutParams;
2425
import androidx.annotation.NonNull;
2526
import androidx.customview.widget.ViewDragHelper;
2627
import com.google.android.material.sidesheet.Sheet.SheetEdge;
@@ -130,4 +131,16 @@ float calculateSlideOffsetBasedOnOutwardEdge(int left) {
130131

131132
return (hiddenOffset - left) / sheetWidth;
132133
}
134+
135+
@Override
136+
void updateCoplanarSiblingLayoutParams(
137+
@NonNull MarginLayoutParams coplanarSiblingLayoutParams, int sheetLeft, int sheetRight) {
138+
int parentWidth = sheetBehavior.getParentWidth();
139+
140+
// Wait until the sheet partially enters the screen to avoid an initial content jump to the
141+
// right edge of the screen.
142+
if (sheetLeft <= parentWidth) {
143+
coplanarSiblingLayoutParams.rightMargin = parentWidth - sheetLeft;
144+
}
145+
}
133146
}

lib/java/com/google/android/material/sidesheet/SheetDelegate.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.google.android.material.sidesheet;
1818

1919
import android.view.View;
20+
import android.view.ViewGroup.MarginLayoutParams;
2021
import androidx.annotation.NonNull;
2122
import com.google.android.material.sidesheet.Sheet.SheetEdge;
2223
import com.google.android.material.sidesheet.Sheet.StableSheetState;
@@ -77,4 +78,8 @@ abstract int calculateTargetStateOnViewReleased(
7778
* sheet is hidden and a value of 1 means that the sheet is fully expanded.
7879
*/
7980
abstract float calculateSlideOffsetBasedOnOutwardEdge(int outwardEdge);
81+
82+
/** Set the coplanar sheet layout params depending on the screen size. */
83+
abstract void updateCoplanarSiblingLayoutParams(
84+
@NonNull MarginLayoutParams coplanarSiblingLayoutParams, int sheetLeft, int sheetRight);
8085
}

lib/java/com/google/android/material/sidesheet/SideSheetBehavior.java

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import android.view.ViewGroup.MarginLayoutParams;
3838
import android.view.ViewParent;
3939
import android.view.accessibility.AccessibilityEvent;
40+
import androidx.annotation.IdRes;
4041
import androidx.annotation.NonNull;
4142
import androidx.annotation.Nullable;
4243
import androidx.annotation.RestrictTo;
@@ -105,6 +106,8 @@ public class SideSheetBehavior<V extends View> extends CoordinatorLayout.Behavio
105106
private int parentWidth;
106107

107108
@Nullable private WeakReference<V> viewRef;
109+
@Nullable private WeakReference<View> coplanarSiblingViewRef;
110+
@IdRes private int coplanarSiblingViewId = View.NO_ID;
108111

109112
@Nullable private VelocityTracker velocityTracker;
110113

@@ -127,6 +130,10 @@ public SideSheetBehavior(@NonNull Context context, @Nullable AttributeSet attrs)
127130
this.shapeAppearanceModel =
128131
ShapeAppearanceModel.builder(context, attrs, 0, DEF_STYLE_RES).build();
129132
}
133+
if (a.hasValue(R.styleable.SideSheetBehavior_Layout_coplanarSiblingViewId)) {
134+
setCoplanarSiblingViewId(
135+
a.getResourceId(R.styleable.SideSheetBehavior_Layout_coplanarSiblingViewId, View.NO_ID));
136+
}
130137
createMaterialShapeDrawableIfNeeded(context);
131138

132139
this.elevation = a.getDimension(R.styleable.SideSheetBehavior_Layout_android_elevation, -1);
@@ -303,6 +310,8 @@ public boolean onLayoutChild(
303310

304311
ViewCompat.offsetLeftAndRight(child, currentOffset);
305312

313+
maybeAssignCoplanarSiblingViewBasedId(parent);
314+
306315
for (SheetCallback callback : callbacks) {
307316
if (callback instanceof SideSheetCallback) {
308317
SideSheetCallback sideSheetCallback = (SideSheetCallback) callback;
@@ -312,6 +321,15 @@ public boolean onLayoutChild(
312321
return true;
313322
}
314323

324+
private void maybeAssignCoplanarSiblingViewBasedId(@NonNull CoordinatorLayout parent) {
325+
if (coplanarSiblingViewRef == null && coplanarSiblingViewId != View.NO_ID) {
326+
View coplanarSiblingView = parent.findViewById(coplanarSiblingViewId);
327+
if (coplanarSiblingView != null) {
328+
this.coplanarSiblingViewRef = new WeakReference<>(coplanarSiblingView);
329+
}
330+
}
331+
}
332+
315333
int getChildWidth() {
316334
return childWidth;
317335
}
@@ -659,6 +677,17 @@ public boolean tryCaptureView(@NonNull View child, int pointerId) {
659677
@Override
660678
public void onViewPositionChanged(
661679
@NonNull View changedView, int left, int top, int dx, int dy) {
680+
View coplanarSiblingView = getCoplanarSiblingView();
681+
if (coplanarSiblingView != null) {
682+
MarginLayoutParams layoutParams =
683+
(MarginLayoutParams) coplanarSiblingView.getLayoutParams();
684+
if (layoutParams != null) {
685+
sheetDelegate.updateCoplanarSiblingLayoutParams(
686+
layoutParams, changedView.getLeft(), changedView.getRight());
687+
coplanarSiblingView.setLayoutParams(layoutParams);
688+
}
689+
}
690+
662691
dispatchOnSlide(changedView, left);
663692
}
664693

@@ -702,6 +731,63 @@ private void dispatchOnSlide(@NonNull View child, int outwardEdge) {
702731
}
703732
}
704733

734+
/**
735+
* Set the sibling id to use for coplanar sheet expansion. If a coplanar sibling has previously
736+
* been set either by this method or via {@link #setCoplanarSiblingView(View)}, that View
737+
* reference will be cleared in favor of this new coplanar sibling reference.
738+
*
739+
* @param coplanarSiblingViewId the id of the coplanar sibling
740+
*/
741+
public void setCoplanarSiblingViewId(@IdRes int coplanarSiblingViewId) {
742+
this.coplanarSiblingViewId = coplanarSiblingViewId;
743+
// Clear any potential coplanar sibling view to make sure that we use this view id rather than
744+
// an existing coplanar sibling view.
745+
clearCoplanarSiblingView();
746+
// Request layout to find the view and trigger a layout pass.
747+
if (viewRef != null) {
748+
View view = viewRef.get();
749+
if (coplanarSiblingViewId != View.NO_ID && ViewCompat.isLaidOut(view)) {
750+
view.requestLayout();
751+
}
752+
}
753+
}
754+
755+
/**
756+
* Set the sibling view to use for coplanar sheet expansion. If a coplanar sibling has previously
757+
* been set either by this method or via {@link #setCoplanarSiblingViewId(int)}, that reference
758+
* will be cleared in favor of this new coplanar sibling reference.
759+
*
760+
* @param coplanarSiblingView the sibling view to squash during coplanar expansion
761+
*/
762+
public void setCoplanarSiblingView(@Nullable View coplanarSiblingView) {
763+
this.coplanarSiblingViewId = View.NO_ID;
764+
if (coplanarSiblingView == null) {
765+
clearCoplanarSiblingView();
766+
} else {
767+
this.coplanarSiblingViewRef = new WeakReference<>(coplanarSiblingView);
768+
// Request layout to make the new view take effect.
769+
if (viewRef != null) {
770+
View view = viewRef.get();
771+
if (ViewCompat.isLaidOut(view)) {
772+
view.requestLayout();
773+
}
774+
}
775+
}
776+
}
777+
778+
/** Returns the sibling view that is used for coplanar sheet expansion. */
779+
@Nullable
780+
public View getCoplanarSiblingView() {
781+
return coplanarSiblingViewRef != null ? coplanarSiblingViewRef.get() : null;
782+
}
783+
784+
private void clearCoplanarSiblingView() {
785+
if (this.coplanarSiblingViewRef != null) {
786+
this.coplanarSiblingViewRef.clear();
787+
}
788+
this.coplanarSiblingViewRef = null;
789+
}
790+
705791
/**
706792
* Checks whether an animation should be smooth after the side sheet is released after dragging.
707793
*

lib/java/com/google/android/material/sidesheet/res/values/attrs.xml

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,30 +17,33 @@
1717
<resources>
1818

1919
<!-- Theme to use for modal side sheet dialogs spawned from this theme. -->
20-
<attr name="sideSheetDialogTheme" format="reference"/>
20+
<attr name="sideSheetDialogTheme" format="reference" />
2121

2222
<!-- Style to use for modal side sheets in the theme. -->
23-
<attr name="sideSheetModalStyle" format="reference"/>
23+
<attr name="sideSheetModalStyle" format="reference" />
2424

2525
<declare-styleable name="SideSheetBehavior_Layout">
2626
<!-- Whether this side sheet is draggable. If not, the app will have to supply different
2727
means to expand and collapse the sheet. Attribute declaration is
2828
in the resources package. -->
29-
<attr name="behavior_draggable"/>
29+
<attr name="behavior_draggable" />
3030
<!-- Shape appearance style reference for side sheet. Attribute declaration is in the shape
3131
package. -->
32-
<attr name="shapeAppearance"/>
32+
<attr name="shapeAppearance" />
3333
<!-- Shape appearance overlay style reference for side sheet. To be used to augment attributes
3434
declared in the shapeAppearance. Attribute declaration is in the shape package. -->
35-
<attr name="shapeAppearanceOverlay"/>
35+
<attr name="shapeAppearanceOverlay" />
3636
<!-- Background color used by the SideSheetBehavior background drawable when shape theming is
3737
enabled. Accepts a ColorStateList or ColorInt. If shape theming is not enabled,
3838
android:background should instead be utilized to set the background resource. -->
39-
<attr name="backgroundTint"/>
39+
<attr name="backgroundTint" />
4040

41-
<attr name="android:elevation"/>
42-
<attr name="android:maxWidth"/>
43-
<attr name="android:maxHeight"/>
41+
<attr name="android:elevation" />
42+
<attr name="android:maxWidth" />
43+
<attr name="android:maxHeight" />
44+
45+
<!-- Id of the coplanar sibling. -->
46+
<attr name="coplanarSiblingViewId" format="reference"/>
4447

4548
</declare-styleable>
4649

0 commit comments

Comments
 (0)