问题
I'm using the BottomSheetBehavior from Google recently released AppCompat v23.2. The height of my bottom sheet depends on the content displayed inside of the bottom sheet (similar to the what Google does themselves in their Maps app).
It works fine with the data loaded initially, but my application changes the content displayed during runtime and when this happens the bottom sheet retains at it's old height, which either leads to unused space at the bottom or a cut of view.
Is there any way to inform the bottom sheet layout to recalculate the height used for expanded state (when height of the ViewGroup is set to MATCH_HEIGHT) or any way to manually set the required height?
EDIT: I also tried to manually call invalidate() on the ViewGroup and the parent of it but without any success.
回答1:
I had the same problem with RelativeLayout as my bottom sheet. The height won't be recalculated. I had to resort to setting the height by the new recalculated value and call BottomSheetBehavior.onLayoutChild.
This is my temporary solution:
coordinatorLayout = (CoordinatorLayout)findViewById(R.id.coordinator_layout);
bottomSheet = findViewById(R.id.bottom_sheet);
int accountHeight = accountTextView.getHeight();
accountTextView.setVisibility(View.GONE);
bottomSheet.getLayoutParams().height = bottomSheet.getHeight() - accountHeight;
bottomSheet.requestLayout();
behavior.onLayoutChild(coordinatorLayout, bottomSheet, ViewCompat.LAYOUT_DIRECTION_LTR);
回答2:
You can use BottomSheetBehavior#setPeekHeight for that.
FrameLayout bottomSheet = (FrameLayout) findViewById(R.id.bottom_sheet);
BottomSheetBehavior<FrameLayout> behavior = BottomSheetBehavior.from(bottomSheet);
behavior.setPeekHeight(newHeight);
This does not automatically move the bottom sheet to the peek height. You can call BottomSheetBehavior#setState to adjust your bottom sheet to the new peek height.
behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
回答3:
Though the issue has been resolved in >=24.0.0 support library, if for some reason you still have to use the older version, here is a workaround.
mBottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull final View bottomSheet, int newState) {
bottomSheet.post(new Runnable() {
@Override
public void run() {
//workaround for the bottomsheet bug
bottomSheet.requestLayout();
bottomSheet.invalidate();
}
});
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
}
});
回答4:
I faced the same issue, when trying to update the peek height based on its contents, the height from a previous layout was found. This makes sense as the new layout had not taken place yet. By posting on the UI thread the layout height is calculated after the new layout, and another layout request is made to update the bottom sheet to the right height.
void show() {
setVisibility(View.VISIBLE);
post(new Runnable() {
@Override
public void run() {
mBottomSheetBehavior.setPeekHeight(findViewById(R.id.sheetPeek).getHeight());
requestLayout();
}
})
}
回答5:
I was facing the same issue when I used a recyclerview inside a BottomSheet and the items changed dynamically. As @sosite has mentioned in his comment, the issue is logged and they have fixed it in the latest release. Issue log here
Just update your design support library to version 24.0.0 and check.
回答6:
I've followed @HaraldUnander advice, and it gave me an idea which has actually worked. If you run a thread (couldn't make it work with the post method as him) after the BottomSheetBehavior.state is set up programmatically to STATE_COLLAPSED, then you can already obtain the height of your views and set the peekHeight depending on it's content.
So first you set the BottomSheetBehavior:
BottomSheetBehavior.from(routeCaptionBottomSheet).state = BottomSheetBehavior.STATE_COLLAPSED
And then you set the peekHeight dynamically:
thread {
activity?.runOnUiThread {
val dynamicHeight = yourContainerView.height
BottomSheetBehavior.from(bottomSheetView).peekHeight = dynamicHeight
}
}
If using Java (I'm using Kotlin with Anko for threads), this could do:
new Thread(new Runnable() {
public void run() {
val dynamicHeight = yourContainerView.height
BottomSheetBehavior.from(bottomSheetView).peekHeight = dynamicHeight
}
}).start();
来源:https://stackoverflow.com/questions/35685681/dynamically-change-height-of-bottomsheetbehavior