Skip to content

Commit

Permalink
[Adaptive][Side Sheet] Added coplanar side sheet with APIs for settin…
Browse files Browse the repository at this point in the history
…g a coplanar sibling view.

PiperOrigin-RevId: 493959543
(cherry picked from commit bc61d6d)
  • Loading branch information
afohrman authored and dsn5ft committed Dec 9, 2022
1 parent 0949e9c commit 8055a2c
Show file tree
Hide file tree
Showing 10 changed files with 409 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,19 @@ public View onCreateDemoView(
modalSideSheetCloseIconButton.setOnClickListener(v -> sideSheetDialog.hide());
}

// Set up coplanar side sheet.
View coplanarSideSheet =
setUpSideSheet(
view,
R.id.coplanar_side_sheet_container,
R.id.show_coplanar_side_sheet_button,
R.id.coplanar_side_sheet_close_icon_button);

setSideSheetCallback(
coplanarSideSheet,
R.id.coplanar_side_sheet_state_text,
R.id.coplanar_side_sheet_slide_offset_text);

return view;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:padding="24dp"
android:gravity="center_horizontal"
android:orientation="vertical">

<Button
android:id="@+id/coplanar_side_sheet_close_icon_button"
style="?attr/materialIconButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/cat_sidesheet_close_button_content_desc"
app:icon="@drawable/ic_close_vd_theme_24px"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />

<TextView
android:id="@+id/coplanar_side_sheet_title_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/cat_sidesheet_coplanar_title"
android:textAppearance="?attr/textAppearanceHeadlineSmall"
app:layout_constraintEnd_toStartOf="@id/coplanar_side_sheet_close_icon_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<androidx.core.widget.NestedScrollView
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/coplanar_side_sheet_title_text">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<TextView
android:id="@+id/coplanar_side_sheet_state_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cat_sidesheet_state_settling"
android:textAppearance="?attr/textAppearanceHeadlineSmall" />

<TextView
android:id="@+id/coplanar_side_sheet_slide_offset_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cat_sidesheet_slide_offset_text"
android:textAppearance="?attr/textAppearanceHeadlineSmall" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cat_sidesheet_filler_text" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/cat_sidesheet_modal_button_show_text" />
<Button
android:id="@+id/show_coplanar_side_sheet_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/cat_sidesheet_coplanar_button_show_text" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
Expand Down Expand Up @@ -96,4 +102,16 @@
<include layout="@layout/cat_sidesheet_content_vertically_scrolling" />
</LinearLayout>

<LinearLayout
android:id="@+id/coplanar_side_sheet_container"
android:layout_width="256dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:orientation="vertical"
app:coplanarSiblingViewId="@id/nested_scroll_view"
app:layout_behavior="@string/side_sheet_behavior"
tools:targetApi="lollipop">
<include layout="@layout/cat_sidesheet_content_coplanar" />
</LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@
Show Modal Side Sheet
</string>

<string name="cat_sidesheet_coplanar_title" description="Title of the coplanar side sheet. [CHAR_LIMIT=NONE]">
Coplanar Side Sheet
</string>
<string name="cat_sidesheet_coplanar_button_show_text" description="Label of button which shows the modal side sheet. [CHAR_LIMIT=NONE]">
Show Coplanar Side Sheet
</string>

<string name="cat_sidesheet_close_button_content_desc" description="Content description for the button to hide the side sheet. [CHAR_LIMIT=NONE]">
Close sheet button
</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import static java.lang.Math.max;

import android.view.View;
import android.view.ViewGroup.MarginLayoutParams;
import androidx.annotation.NonNull;
import androidx.customview.widget.ViewDragHelper;
import com.google.android.material.sidesheet.Sheet.SheetEdge;
Expand Down Expand Up @@ -130,4 +131,16 @@ float calculateSlideOffsetBasedOnOutwardEdge(int left) {

return (hiddenOffset - left) / sheetWidth;
}

@Override
void updateCoplanarSiblingLayoutParams(
@NonNull MarginLayoutParams coplanarSiblingLayoutParams, int sheetLeft, int sheetRight) {
int parentWidth = sheetBehavior.getParentWidth();

// Wait until the sheet partially enters the screen to avoid an initial content jump to the
// right edge of the screen.
if (sheetLeft <= parentWidth) {
coplanarSiblingLayoutParams.rightMargin = parentWidth - sheetLeft;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.google.android.material.sidesheet;

import android.view.View;
import android.view.ViewGroup.MarginLayoutParams;
import androidx.annotation.NonNull;
import com.google.android.material.sidesheet.Sheet.SheetEdge;
import com.google.android.material.sidesheet.Sheet.StableSheetState;
Expand Down Expand Up @@ -77,4 +78,8 @@ abstract int calculateTargetStateOnViewReleased(
* sheet is hidden and a value of 1 means that the sheet is fully expanded.
*/
abstract float calculateSlideOffsetBasedOnOutwardEdge(int outwardEdge);

/** Set the coplanar sheet layout params depending on the screen size. */
abstract void updateCoplanarSiblingLayoutParams(
@NonNull MarginLayoutParams coplanarSiblingLayoutParams, int sheetLeft, int sheetRight);
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import android.view.ViewGroup.MarginLayoutParams;
import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
Expand Down Expand Up @@ -105,6 +106,8 @@ public class SideSheetBehavior<V extends View> extends CoordinatorLayout.Behavio
private int parentWidth;

@Nullable private WeakReference<V> viewRef;
@Nullable private WeakReference<View> coplanarSiblingViewRef;
@IdRes private int coplanarSiblingViewId = View.NO_ID;

@Nullable private VelocityTracker velocityTracker;

Expand All @@ -127,6 +130,10 @@ public SideSheetBehavior(@NonNull Context context, @Nullable AttributeSet attrs)
this.shapeAppearanceModel =
ShapeAppearanceModel.builder(context, attrs, 0, DEF_STYLE_RES).build();
}
if (a.hasValue(R.styleable.SideSheetBehavior_Layout_coplanarSiblingViewId)) {
setCoplanarSiblingViewId(
a.getResourceId(R.styleable.SideSheetBehavior_Layout_coplanarSiblingViewId, View.NO_ID));
}
createMaterialShapeDrawableIfNeeded(context);

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

ViewCompat.offsetLeftAndRight(child, currentOffset);

maybeAssignCoplanarSiblingViewBasedId(parent);

for (SheetCallback callback : callbacks) {
if (callback instanceof SideSheetCallback) {
SideSheetCallback sideSheetCallback = (SideSheetCallback) callback;
Expand All @@ -312,6 +321,15 @@ public boolean onLayoutChild(
return true;
}

private void maybeAssignCoplanarSiblingViewBasedId(@NonNull CoordinatorLayout parent) {
if (coplanarSiblingViewRef == null && coplanarSiblingViewId != View.NO_ID) {
View coplanarSiblingView = parent.findViewById(coplanarSiblingViewId);
if (coplanarSiblingView != null) {
this.coplanarSiblingViewRef = new WeakReference<>(coplanarSiblingView);
}
}
}

int getChildWidth() {
return childWidth;
}
Expand Down Expand Up @@ -659,6 +677,17 @@ public boolean tryCaptureView(@NonNull View child, int pointerId) {
@Override
public void onViewPositionChanged(
@NonNull View changedView, int left, int top, int dx, int dy) {
View coplanarSiblingView = getCoplanarSiblingView();
if (coplanarSiblingView != null) {
MarginLayoutParams layoutParams =
(MarginLayoutParams) coplanarSiblingView.getLayoutParams();
if (layoutParams != null) {
sheetDelegate.updateCoplanarSiblingLayoutParams(
layoutParams, changedView.getLeft(), changedView.getRight());
coplanarSiblingView.setLayoutParams(layoutParams);
}
}

dispatchOnSlide(changedView, left);
}

Expand Down Expand Up @@ -702,6 +731,63 @@ private void dispatchOnSlide(@NonNull View child, int outwardEdge) {
}
}

/**
* Set the sibling id to use for coplanar sheet expansion. If a coplanar sibling has previously
* been set either by this method or via {@link #setCoplanarSiblingView(View)}, that View
* reference will be cleared in favor of this new coplanar sibling reference.
*
* @param coplanarSiblingViewId the id of the coplanar sibling
*/
public void setCoplanarSiblingViewId(@IdRes int coplanarSiblingViewId) {
this.coplanarSiblingViewId = coplanarSiblingViewId;
// Clear any potential coplanar sibling view to make sure that we use this view id rather than
// an existing coplanar sibling view.
clearCoplanarSiblingView();
// Request layout to find the view and trigger a layout pass.
if (viewRef != null) {
View view = viewRef.get();
if (coplanarSiblingViewId != View.NO_ID && ViewCompat.isLaidOut(view)) {
view.requestLayout();
}
}
}

/**
* Set the sibling view to use for coplanar sheet expansion. If a coplanar sibling has previously
* been set either by this method or via {@link #setCoplanarSiblingViewId(int)}, that reference
* will be cleared in favor of this new coplanar sibling reference.
*
* @param coplanarSiblingView the sibling view to squash during coplanar expansion
*/
public void setCoplanarSiblingView(@Nullable View coplanarSiblingView) {
this.coplanarSiblingViewId = View.NO_ID;
if (coplanarSiblingView == null) {
clearCoplanarSiblingView();
} else {
this.coplanarSiblingViewRef = new WeakReference<>(coplanarSiblingView);
// Request layout to make the new view take effect.
if (viewRef != null) {
View view = viewRef.get();
if (ViewCompat.isLaidOut(view)) {
view.requestLayout();
}
}
}
}

/** Returns the sibling view that is used for coplanar sheet expansion. */
@Nullable
public View getCoplanarSiblingView() {
return coplanarSiblingViewRef != null ? coplanarSiblingViewRef.get() : null;
}

private void clearCoplanarSiblingView() {
if (this.coplanarSiblingViewRef != null) {
this.coplanarSiblingViewRef.clear();
}
this.coplanarSiblingViewRef = null;
}

/**
* Checks whether an animation should be smooth after the side sheet is released after dragging.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,33 @@
<resources>

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

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

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

<attr name="android:elevation"/>
<attr name="android:maxWidth"/>
<attr name="android:maxHeight"/>
<attr name="android:elevation" />
<attr name="android:maxWidth" />
<attr name="android:maxHeight" />

<!-- Id of the coplanar sibling. -->
<attr name="coplanarSiblingViewId" format="reference"/>

</declare-styleable>

Expand Down
Loading

0 comments on commit 8055a2c

Please sign in to comment.