I would like to have my bottomsheet
expanded only up to appbar
. I have viewpager
with tabs, and viewpager
has appbar_scrolling_view_behavior
, so then list inside it is scrolled the toolbar
is collapsed. But the bottom sheet is expanded, which is the behaviour I do not want to have. Basically I would like to have collapsed bottomsheet
stay in place with the same height, and in expanded mode it should expand only up to toolbar
, no matter if the toolbar
is collapsed or not.
Here is how my xml looks like. This works, but the bottom sheet also reacts this way to appbar
collapsing.
If I remove behaviour from second CoordinatorLayout
the bottomsheet
stays in place, but gets expanded to full screen.
<android.support.design.widget.CoordinatorLayout android:id="@+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways" />
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="@+id/loadingContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
... content with viewpager
</FrameLayout>
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:id="@+id/bottomSheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:behavior_hideable="false"
app:behavior_peekHeight="55dp"
app:layout_behavior="@string/bottom_sheet_behavior"/>
</android.support.design.widget.CoordinatorLayout>
</android.support.design.widget.CoordinatorLayout>
I actually fixed this myself by writing my own Behaviour for the bottomSheet to recalculate itself. Also placed all elements inside the CoordinatorLayout.
public class BottomSheetBehaviour extends AppBarLayout.ScrollingViewBehavior {
public BottomSheetBehaviour () { }
public BottomSheetBehaviour (Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency instanceof AppBarLayout;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
setDimensions((CoordinatorLayout) child, child.getLayoutParams().width,
parent.getHeight() - (int) getOffset(parent));
return true;
}
@Override
protected void layoutChild(final CoordinatorLayout parent, final View child, final int layoutDirection) {
final List<View> dependencies = parent.getDependencies(child);
final View header = findFirstDependency(dependencies);
final Rect available = new Rect();
if (header != null) {
final CoordinatorLayout.LayoutParams lp =
(CoordinatorLayout.LayoutParams) child.getLayoutParams();
available.set(parent.getPaddingLeft() + lp.leftMargin, header.getBottom() + lp.topMargin,
parent.getWidth() - parent.getPaddingRight() - lp.rightMargin,
parent.getHeight() + header.getBottom() - parent.getPaddingBottom() - lp.bottomMargin);
final Rect out = new Rect();
GravityCompat.apply(resolveGravity(lp.gravity), child.getMeasuredWidth(),
child.getMeasuredHeight(), available, out, layoutDirection);
final int overlap = getOverlapPixelsForOffset();
child.layout(out.left, out.top - overlap, out.right, parent.getHeight() - overlap);
}
}
private int getOverlapPixelsForOffset() {
return getOverlayTop() == 0 ? 0 :
constrain((int) (1f * getOverlayTop()), 0, getOverlayTop());
}
private AppBarLayout findFirstDependency(List<View> views) {
for (int i = 0, z = views.size(); i < z; i++) {
View view = views.get(i);
if (view instanceof AppBarLayout) {
return (AppBarLayout) view;
}
}
return null;
}
private static int constrain(int amount, int low, int high) {
return amount < low ? low : (amount > high ? high : amount);
}
private static int resolveGravity(int gravity) {
return gravity == Gravity.NO_GRAVITY ? GravityCompat.START | Gravity.TOP : gravity;
}
private void setDimensions(CoordinatorLayout view, int width, int height) {
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) view.getLayoutParams();
params.width = width;
params.height = height;
view.setLayoutParams(params);
}
private float getOffset(CoordinatorLayout coordinatorLayout) {
for (int i = 0; i < coordinatorLayout.getChildCount(); i++) {
View child = coordinatorLayout.getChildAt(i);
if (child instanceof AppBarLayout) {
return child.getY() + child.getHeight();
}
}
return 0;
}
}
Solution is kind of complex, but I couldn't find any other better way to solve this. So if anyone knows better solution to this case please post and I'll investigate it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With