Skip to content

Commit

Permalink
[Predictive Back][Side Sheet] Added predictive back support for stand…
Browse files Browse the repository at this point in the history
…ard side sheets.

PiperOrigin-RevId: 527326750
  • Loading branch information
afohrman authored and leticiarossi committed Apr 26, 2023
1 parent 29b59c2 commit 562285e
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 39 deletions.
Expand Up @@ -20,6 +20,7 @@

import static android.view.View.NO_ID;

import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
Expand All @@ -30,11 +31,14 @@
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.window.BackEvent;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.GravityInt;
import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.StringRes;
import androidx.annotation.StyleRes;
import androidx.coordinatorlayout.widget.CoordinatorLayout.LayoutParams;
Expand Down Expand Up @@ -96,7 +100,8 @@ public View onCreateDemoView(
view,
R.id.standard_side_sheet_container,
R.id.show_standard_side_sheet_button,
R.id.close_icon_button);
R.id.close_icon_button,
/* shouldHandleBack= */ true);

setSideSheetCallback(
standardRightSideSheet, R.id.side_sheet_state_text, R.id.side_sheet_slide_offset_text);
Expand All @@ -107,7 +112,8 @@ public View onCreateDemoView(
view,
R.id.standard_detached_side_sheet_container,
R.id.show_standard_detached_side_sheet_button,
R.id.detached_close_icon_button);
R.id.detached_close_icon_button,
/* shouldHandleBack= */ true);

setSideSheetCallback(
detachedStandardSideSheet,
Expand All @@ -120,7 +126,8 @@ public View onCreateDemoView(
view,
R.id.vertically_scrolling_side_sheet_container,
R.id.show_vertically_scrolling_side_sheet_button,
R.id.vertically_scrolling_side_sheet_close_icon_button);
R.id.vertically_scrolling_side_sheet_close_icon_button,
/* shouldHandleBack= */ true);

setSideSheetCallback(
verticallyScrollingSideSheet,
Expand All @@ -141,7 +148,8 @@ public View onCreateDemoView(
view,
R.id.coplanar_side_sheet_container,
R.id.show_coplanar_side_sheet_button,
R.id.coplanar_side_sheet_close_icon_button);
R.id.coplanar_side_sheet_close_icon_button,
/* shouldHandleBack= */ false);

setSideSheetCallback(
coplanarSideSheet,
Expand All @@ -154,7 +162,8 @@ public View onCreateDemoView(
view,
R.id.coplanar_detached_side_sheet_container,
R.id.show_coplanar_detached_side_sheet_button,
R.id.coplanar_detached_side_sheet_close_icon_button);
R.id.coplanar_detached_side_sheet_close_icon_button,
/* shouldHandleBack= */ false);

setSideSheetCallback(
detachedCoplanarSideSheet,
Expand All @@ -165,8 +174,7 @@ public View onCreateDemoView(
}

private void setUpSheetGravityButtonToggleGroup(@NonNull View view) {
sheetGravityButtonToggleGroup =
view.findViewById(R.id.sheet_gravity_button_toggle_group);
sheetGravityButtonToggleGroup = view.findViewById(R.id.sheet_gravity_button_toggle_group);
// Check the button corresponding to end sheet gravity, which is the default.
sheetGravityButtonToggleGroup.check(R.id.end_gravity_button);
sheetGravityButtonToggleGroup.addOnButtonCheckedListener(
Expand All @@ -185,11 +193,39 @@ private void setUpSheetGravityButtonToggleGroup(@NonNull View view) {
});
}

private void setupBackHandling(SideSheetBehavior<View> sideSheetBehavior) {
OnBackPressedCallback nonModalOnBackPressedCallback =
createNonModalOnBackPressedCallback(sideSheetBehavior);
requireActivity().getOnBackPressedDispatcher().addCallback(this, nonModalOnBackPressedCallback);
sideSheetBehavior.addCallback(
new SideSheetCallback() {
@Override
public void onStateChanged(@NonNull View sheet, int newState) {
switch (newState) {
case SideSheetBehavior.STATE_EXPANDED:
case SideSheetBehavior.STATE_SETTLING:
nonModalOnBackPressedCallback.setEnabled(true);
break;
case SideSheetBehavior.STATE_HIDDEN:
nonModalOnBackPressedCallback.setEnabled(false);
break;
case SideSheetBehavior.STATE_DRAGGING:
default:
break;
}
}

@Override
public void onSlide(@NonNull View sheet, float slideOffset) {}
});
}

private View setUpSideSheet(
@NonNull View view,
@IdRes int sideSheetContainerId,
@IdRes int showSideSheetButtonId,
@IdRes int closeIconButtonId) {
@IdRes int closeIconButtonId,
boolean shouldHandleBack) {
View sideSheet = view.findViewById(sideSheetContainerId);
SideSheetBehavior<View> sideSheetBehavior = SideSheetBehavior.from(sideSheet);

Expand All @@ -199,6 +235,10 @@ private View setUpSideSheet(
View standardSideSheetCloseIconButton = sideSheet.findViewById(closeIconButtonId);
standardSideSheetCloseIconButton.setOnClickListener(v -> hideSideSheet(sideSheetBehavior));

if (shouldHandleBack) {
setupBackHandling(sideSheetBehavior);
}

sideSheetViews.add(sideSheet);

return sideSheet;
Expand Down Expand Up @@ -258,37 +298,39 @@ private void setUpModalSheet(
@StringRes int sheetTitleStringRes,
@NonNull Button showSheetButton,
@IdRes int closeIconButtonIdRes) {
showSheetButton.setOnClickListener(v1 -> {
SideSheetDialog sheetDialog =
sheetThemeOverlayRes == NO_ID
? new SideSheetDialog(requireContext())
: new SideSheetDialog(requireContext(), sheetThemeOverlayRes);

sheetDialog.setContentView(sheetContentLayoutRes);
View modalSheetContent = sheetDialog.findViewById(sheetContentRootIdRes);
if (modalSheetContent != null) {
TextView modalSideSheetTitle = modalSheetContent.findViewById(sheetTitleIdRes);
modalSideSheetTitle.setText(sheetTitleStringRes);
}
new WindowPreferencesManager(requireContext())
.applyEdgeToEdgePreference(sheetDialog.getWindow());

sheetDialog
.getBehavior()
.addCallback(
createSideSheetCallback(
sheetDialog.findViewById(R.id.side_sheet_state_text),
sheetDialog.findViewById(R.id.side_sheet_slide_offset_text)));

sheetDialog.setSheetEdge(getGravityForIdRes(sheetGravityButtonToggleGroup.getCheckedButtonId()));

View modalSideSheetCloseIconButton = sheetDialog.findViewById(closeIconButtonIdRes);
if (modalSideSheetCloseIconButton != null) {
modalSideSheetCloseIconButton.setOnClickListener(v2 -> sheetDialog.hide());
}
showSheetButton.setOnClickListener(
v1 -> {
SideSheetDialog sheetDialog =
sheetThemeOverlayRes == NO_ID
? new SideSheetDialog(requireContext())
: new SideSheetDialog(requireContext(), sheetThemeOverlayRes);

sheetDialog.setContentView(sheetContentLayoutRes);
View modalSheetContent = sheetDialog.findViewById(sheetContentRootIdRes);
if (modalSheetContent != null) {
TextView modalSideSheetTitle = modalSheetContent.findViewById(sheetTitleIdRes);
modalSideSheetTitle.setText(sheetTitleStringRes);
}
new WindowPreferencesManager(requireContext())
.applyEdgeToEdgePreference(sheetDialog.getWindow());

sheetDialog
.getBehavior()
.addCallback(
createSideSheetCallback(
sheetDialog.findViewById(R.id.side_sheet_state_text),
sheetDialog.findViewById(R.id.side_sheet_slide_offset_text)));

sheetDialog.setSheetEdge(
getGravityForIdRes(sheetGravityButtonToggleGroup.getCheckedButtonId()));

View modalSideSheetCloseIconButton = sheetDialog.findViewById(closeIconButtonIdRes);
if (modalSideSheetCloseIconButton != null) {
modalSideSheetCloseIconButton.setOnClickListener(v2 -> sheetDialog.hide());
}

sheetDialog.show();
});
sheetDialog.show();
});
}

private void setUpToolbar(@NonNull View view) {
Expand Down Expand Up @@ -364,4 +406,32 @@ public void onSlide(@NonNull View sheet, float slideOffset) {
}
};
}

private OnBackPressedCallback createNonModalOnBackPressedCallback(
SideSheetBehavior<View> behavior) {
return new OnBackPressedCallback(/* enabled= */ false) {
@RequiresApi(VERSION_CODES.UPSIDE_DOWN_CAKE)
@Override
public void handleOnBackStarted(@NonNull BackEvent backEvent) {
behavior.startBackProgress(backEvent);
}

@RequiresApi(VERSION_CODES.UPSIDE_DOWN_CAKE)
@Override
public void handleOnBackProgressed(@NonNull BackEvent backEvent) {
behavior.updateBackProgress(backEvent);
}

@Override
public void handleOnBackPressed() {
behavior.handleBackInvoked();
}

@RequiresApi(VERSION_CODES.UPSIDE_DOWN_CAKE)
@Override
public void handleOnBackCancelled() {
behavior.cancelBackProgress();
}
};
}
}
3 changes: 2 additions & 1 deletion lib/java/com/google/android/material/sidesheet/Sheet.java
Expand Up @@ -20,14 +20,15 @@

import androidx.annotation.IntDef;
import androidx.annotation.RestrictTo;
import com.google.android.material.motion.MaterialBackHandler;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
* Interface for sheet constants and {@code IntDefs} to be shared between the different {@link
* Sheet} implementations.
*/
interface Sheet<C extends SheetCallback> {
interface Sheet<C extends SheetCallback> extends MaterialBackHandler {
/** The sheet is dragging. */
int STATE_DRAGGING = 1;

Expand Down

0 comments on commit 562285e

Please sign in to comment.