Commit e2acd096 authored by Jordan Demeulenaere's avatar Jordan Demeulenaere Committed by Commit Bot

Improve wrapped BottomSheetContent support.

This CL improves the support of wrapped BottomSheetContent by:
 * ensuring that we don't force the wrapped content height to be equal to
   the BottomSheet height.
 * introducing a SizeListenable interface than can be implemented by
   content views to notify when their size changed. This can be used by
   contents whose height is animated.

Bug: 933070
Change-Id: Ib9b11e239f6c24e1bcbe57303a9c4ce5e8078723
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1552844
Commit-Queue: Jordan Demeulenaere <jdemeulenaere@chromium.org>
Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Cr-Commit-Position: refs/heads/master@{#649811}
parent f618cf2b
...@@ -328,6 +328,18 @@ public class BottomSheet ...@@ -328,6 +328,18 @@ public class BottomSheet
return false; return false;
} }
/**
* Set a {@link ContentSizeListener} that should be notified when the size of the content
* has changed. This will be called only if {@link #wrapContentEnabled()} returns {@code
* true}. Note that you need to implement this method only if the content view height
* changes are animated.
*
* @return Whether the listener was correctly set.
*/
default boolean setContentSizeListener(@Nullable ContentSizeListener listener) {
return false;
}
/** /**
* @return The resource id of the content description for the bottom sheet. This is * @return The resource id of the content description for the bottom sheet. This is
* generally the name of the feature/content that is showing. 'Swipe down to close.' * generally the name of the feature/content that is showing. 'Swipe down to close.'
...@@ -354,6 +366,12 @@ public class BottomSheet ...@@ -354,6 +366,12 @@ public class BottomSheet
int getSheetClosedAccessibilityStringId(); int getSheetClosedAccessibilityStringId();
} }
/** Interface to listen when the size of a BottomSheetContent changes. */
public interface ContentSizeListener {
/** Called when the size of the view has changed. */
void onSizeChanged(int width, int height, int oldWidth, int oldHeight);
}
/** /**
* Returns whether the provided bottom sheet state is in one of the stable open or closed * Returns whether the provided bottom sheet state is in one of the stable open or closed
* states: {@link #SheetState.FULL}, {@link #SheetState.PEEK} or {@link #SheetState.HALF} * states: {@link #SheetState.FULL}, {@link #SheetState.PEEK} or {@link #SheetState.HALF}
...@@ -517,7 +535,10 @@ public class BottomSheet ...@@ -517,7 +535,10 @@ public class BottomSheet
int heightSize = MeasureSpec.getSize(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec);
assert heightSize != 0; assert heightSize != 0;
int height = heightSize + mToolbarShadowHeight; int height = heightSize + mToolbarShadowHeight;
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); int mode = mSheetContent != null && mSheetContent.wrapContentEnabled()
? MeasureSpec.AT_MOST
: MeasureSpec.EXACTLY;
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, mode));
} }
/** /**
...@@ -768,7 +789,13 @@ public class BottomSheet ...@@ -768,7 +789,13 @@ public class BottomSheet
@Override @Override
public float getMaxOffsetPx() { public float getMaxOffsetPx() {
return getFullRatio() * mContainerHeight; float maxOffset = getFullRatio() * mContainerHeight;
if (mSheetContent != null && mSheetContent.wrapContentEnabled()) {
ensureContentDesiredHeightIsComputed();
return Math.min(maxOffset, mContentDesiredHeight + mToolbarShadowHeight);
}
return maxOffset;
} }
/** /**
...@@ -782,8 +809,9 @@ public class BottomSheet ...@@ -782,8 +809,9 @@ public class BottomSheet
// If the desired content is already showing, do nothing. // If the desired content is already showing, do nothing.
if (mSheetContent == content) return; if (mSheetContent == content) return;
// Remove this as listener from previous content layout changes. // Remove this as listener from previous content layout and size changes.
if (mSheetContent != null) { if (mSheetContent != null) {
mSheetContent.setContentSizeListener(null);
mSheetContent.getContentView().removeOnLayoutChangeListener(this); mSheetContent.getContentView().removeOnLayoutChangeListener(this);
} }
...@@ -1374,19 +1402,24 @@ public class BottomSheet ...@@ -1374,19 +1402,24 @@ public class BottomSheet
public float getSheetHeightForState(@SheetState int state) { public float getSheetHeightForState(@SheetState int state) {
if (mSheetContent != null && mSheetContent.wrapContentEnabled() if (mSheetContent != null && mSheetContent.wrapContentEnabled()
&& state == SheetState.FULL) { && state == SheetState.FULL) {
if (mContentDesiredHeight == HEIGHT_UNSPECIFIED) { ensureContentDesiredHeightIsComputed();
mSheetContent.getContentView().measure( return mContentDesiredHeight + mToolbarShadowHeight;
MeasureSpec.makeMeasureSpec((int) mContainerWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec((int) mContainerHeight, MeasureSpec.AT_MOST));
mContentDesiredHeight =
mSheetContent.getContentView().getMeasuredHeight() + mToolbarShadowHeight;
}
return mContentDesiredHeight;
} }
return getRatioForState(state) * mContainerHeight; return getRatioForState(state) * mContainerHeight;
} }
private void ensureContentDesiredHeightIsComputed() {
if (mContentDesiredHeight != HEIGHT_UNSPECIFIED) {
return;
}
mSheetContent.getContentView().measure(
MeasureSpec.makeMeasureSpec((int) mContainerWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec((int) mContainerHeight, MeasureSpec.AT_MOST));
mContentDesiredHeight = mSheetContent.getContentView().getMeasuredHeight();
}
private float getRatioForState(int state) { private float getRatioForState(int state) {
switch (state) { switch (state) {
case SheetState.HIDDEN: case SheetState.HIDDEN:
...@@ -1530,8 +1563,13 @@ public class BottomSheet ...@@ -1530,8 +1563,13 @@ public class BottomSheet
mSheetContent = content; mSheetContent = content;
if (content != null && content.wrapContentEnabled()) { if (content != null && content.wrapContentEnabled()) {
// Listen for layout/size changes.
if (!content.setContentSizeListener(this::onContentSizeChanged)) {
content.getContentView().addOnLayoutChangeListener(this); content.getContentView().addOnLayoutChangeListener(this);
ensureContentIsWrapped(); }
invalidateContentDesiredHeight();
ensureContentIsWrapped(/* animate= */ true);
// HALF state is forbidden when wrapping the content. // HALF state is forbidden when wrapping the content.
if (mCurrentState == SheetState.HALF) { if (mCurrentState == SheetState.HALF) {
...@@ -1551,12 +1589,19 @@ public class BottomSheet ...@@ -1551,12 +1589,19 @@ public class BottomSheet
@Override @Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) { int oldTop, int oldRight, int oldBottom) {
ensureContentIsWrapped(); invalidateContentDesiredHeight();
ensureContentIsWrapped(/* animate= */ true);
} }
private void ensureContentIsWrapped() { /**
invalidateContentDesiredHeight(); * Called when the sheet content size changed.
*/
private void onContentSizeChanged(int width, int height, int oldWidth, int oldHeight) {
mContentDesiredHeight = height;
ensureContentIsWrapped(/* animate= */ false);
}
private void ensureContentIsWrapped(boolean animate) {
if (mCurrentState == SheetState.HIDDEN || mCurrentState == SheetState.PEEK) return; if (mCurrentState == SheetState.HIDDEN || mCurrentState == SheetState.PEEK) return;
// The SCROLLING state is used when animating the sheet height or when the user is swiping // The SCROLLING state is used when animating the sheet height or when the user is swiping
...@@ -1564,7 +1609,7 @@ public class BottomSheet ...@@ -1564,7 +1609,7 @@ public class BottomSheet
cancelAnimation(); cancelAnimation();
if (mCurrentState == SheetState.SCROLLING) return; if (mCurrentState == SheetState.SCROLLING) return;
createSettleAnimation(mCurrentState, StateChangeReason.NONE); setSheetState(mCurrentState, animate);
} }
private void invalidateContentDesiredHeight() { private void invalidateContentDesiredHeight() {
......
...@@ -93,6 +93,11 @@ public class TestBottomSheetContent implements BottomSheetContent { ...@@ -93,6 +93,11 @@ public class TestBottomSheetContent implements BottomSheetContent {
return mHasCustomLifecycle; return mHasCustomLifecycle;
} }
@Override
public boolean setContentSizeListener(@Nullable BottomSheet.ContentSizeListener listener) {
return false;
}
@Override @Override
public int getSheetContentDescriptionStringId() { public int getSheetContentDescriptionStringId() {
return R.string.contextual_suggestions_button_description; return R.string.contextual_suggestions_button_description;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment