如何模仿谷歌地图的底部表3阶段的行为?

背景资料

我被分配制作一个 UI,其行为类似于谷歌地图显示找到的结果的底部表格。

它有三个不同的阶段:

  1. 底部内容。上部区域仍然是可触摸的,不会在底部滚动任何东西
  2. 全屏内容,而上面的区域有一个大的标题。
  3. 全屏内容,而上面的区域只有工具栏。

这就是我在谷歌地图上说的:

Enter image description here

问题是

问题是,底部的工作表还没有成为设计库的一部分(尽管它是被请求的,这里)。

Not only that, but the UI seems quite complex and needs handling of the toolbar on multiple phases.

我已经尽力了

我已经找到了一个很好的(足够的)底部页面库(这里) ,并添加了内容到它的片段样本,有大约相同的视图显示在材料设计样本(如 here) ,有一个 CollapsingToolbarLayout,将照顾阶段2 + 3。

在我正在开发的应用程序中,我还必须在你滚动时移动一个图标,但我认为如果我在其他方面成功了,这应该会很容易。 密码是这样的:

片段 _ my. xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
android:id="@+id/main_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">


<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="@dimen/detail_backdrop_height"


android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">


<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"


app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">


<ImageView
android:id="@+id/backdrop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"/>


<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>


<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">


<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="24dp">


<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/card_margin">


<LinearLayout
style="@style/Widget.CardContent"
android:layout_width="match_parent"
android:layout_height="wrap_content">


<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Info"
android:textAppearance="@style/TextAppearance.AppCompat.Title"/>


<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/cheese_ipsum"/>
</LinearLayout>
</android.support.v7.widget.CardView>


<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/card_margin"
android:layout_marginLeft="@dimen/card_margin"
android:layout_marginRight="@dimen/card_margin">


<LinearLayout
style="@style/Widget.CardContent"
android:layout_width="match_parent"
android:layout_height="wrap_content">


<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Friends"
android:textAppearance="@style/TextAppearance.AppCompat.Title"/>


<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/cheese_ipsum"/>
</LinearLayout>
</android.support.v7.widget.CardView>


<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/card_margin"
android:layout_marginLeft="@dimen/card_margin"
android:layout_marginRight="@dimen/card_margin">


<LinearLayout
style="@style/Widget.CardContent"
android:layout_width="match_parent"
android:layout_height="wrap_content">


<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Related"
android:textAppearance="@style/TextAppearance.AppCompat.Title"/>


<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/cheese_ipsum"/>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>


<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/fab_margin"
android:clickable="true"
android:src="@android:drawable/ic_menu_send"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|right|end"/>


</android.support.design.widget.CoordinatorLayout>

# # 我的碎片,java #

public class MyFragment extends BottomSheetFragment {


@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_my, container, false);
view.setMinimumHeight(getResources().getDisplayMetrics().heightPixels);
CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) view.findViewById(R.id.collapsing_toolbar);
collapsingToolbar.setTitle("AAA");
final Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
final AppCompatActivity activity = (AppCompatActivity) getActivity();
activity.setSupportActionBar(toolbar);
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//toolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NavUtils.navigateUpFromSameTask(getActivity());
}
});
final ImageView imageView = (ImageView) view.findViewById(R.id.backdrop);


Glide.with(this).load(R.drawable.cheese_1).centerCrop().into(imageView);
return view;
}
}

# # # # BottomSheetFragmentActivity.java

public final class BottomSheetFragmentActivity extends AppCompatActivity {


protected BottomSheetLayout bottomSheetLayout;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bottom_sheet_fragment);
bottomSheetLayout = (BottomSheetLayout) findViewById(R.id.bottomsheet);
findViewById(R.id.bottomsheet_fragment_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new MyFragment().show(getSupportFragmentManager(), R.id.bottomsheet);
}
});
bottomSheetLayout.setShouldDimContentView(false);
bottomSheetLayout.setPeekOnDismiss(true);
bottomSheetLayout.setPeekSheetTranslation(200);
bottomSheetLayout.setInterceptContentTouch(false);
bottomSheetLayout.setDefaultViewTransformer(new BaseViewTransformer() {
@Override
public void transformView(final float translation, final float maxTranslation, final float peekedTranslation, final BottomSheetLayout parent, final View view) {
Log.d("AppLog", "translation:" + translation + " maxTranslation:" + maxTranslation + " peekedTranslation:" + peekedTranslation);
}
});
}
}

它几乎运行良好,唯一的问题是从第三名回到第二名:

enter image description here

那个问题

代码出了什么问题? 为了实现所需的行为,我可以做些什么?

38393 次浏览

注意 : 阅读底部的编辑


好的,我已经找到了一种方法,但是我不得不修改多个类的代码,这样底部的表就会知道 appBarLayout 的状态(是否展开) ,并且忽略向上滚动,以防它没有展开:

BottomSheetLayout.java

新增字段:

private AppBarLayout mAppBarLayout;
private OnOffsetChangedListener mOnOffsetChangedListener;
private int mAppBarLayoutOffset;

Init ()-添加了以下内容:

    mOnOffsetChangedListener = new OnOffsetChangedListener() {
@Override
public void onOffsetChanged(final AppBarLayout appBarLayout, final int verticalOffset) {
mAppBarLayoutOffset = verticalOffset;
}
};

增加了设置 appBarLayout 的功能:

public void setAppBarLayout(final AppBarLayout appBarLayout) {
if (mAppBarLayout == appBarLayout)
return;
if (mAppBarLayout != null)
mAppBarLayout.removeOnOffsetChangedListener(mOnOffsetChangedListener);
mAppBarLayout = appBarLayout;
mAppBarLayout.addOnOffsetChangedListener(mOnOffsetChangedListener);
}

OnDetachedFromWindow ()-添加以下内容:

    if (mAppBarLayout != null)
mAppBarLayout.removeOnOffsetChangedListener(mOnOffsetChangedListener);

OnTouchEvent ()-添加了以下内容:

      ...
if (bottomSheetOwnsTouch) {
if (state == State.EXPANDED && scrollingDown && mAppBarLayout != null && mAppBarLayoutOffset != 0) {
event.offsetLocation(0, sheetTranslation - getHeight());
getSheetView().dispatchTouchEvent(event);
return true;
}
...

这些就是主要的变化,现在说说它们的成因:

Java

OnCreateView ()-添加了以下内容:

    mBottomSheetLayout.setAppBarLayout((AppBarLayout) view.findViewById(R.id.appbar));

我还添加了这个函数:

 public void setBottomSheetLayout(final BottomSheetLayout bottomSheetLayout) {
mBottomSheetLayout = bottomSheetLayout;
}

这就是活动告诉片段 appBarLayout 的方式:

            final MyFragment myFragment = new MyFragment();
myFragment.setBottomSheetLayout(bottomSheetLayout);
myFragment.show(getSupportFragmentManager(), R.id.bottomsheet);

这个项目现在可以在 GitHub 上找到:

https://github.com/AndroidDeveloperLB/ThreePhasesBottomSheet

我希望它没有虫子。


遗憾的是,这个解决方案存在缺陷,所以我不会把这个答案标记为正确答案:

  1. It only works well on Android 6 and above. Others have a weird behavior of showing the bottom sheet expanded for a tiny fraction of a time, each time when showing it.
  2. 方向更改根本不能保存滚动的状态,所以我禁用了它。
  3. 当底部页面仍然折叠(在底部)时,能够滚动到底部页面内容的罕见问题
  4. 如果之前显示过键盘,那么当试图偷看时,底部的工作表可能是全屏的。

如果有人能帮忙的话,尽管说。


For issue #1, I've tried adding a fix by setting the visibility to INVISIBLE when the bottom sheet doesn't peek yet, but it doesn't always work, especially if a keyboard is shown.


对于问题 # 1,我已经找到了修复它的方法,只需将其包装(在“善后”中)。我使用了 FrameLayout) ,并且在其中放入了一个全尺寸的视图(我只是放入了“ View”) ,如下所示:

<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--This full sized view, together with the FrameLayout above, are used to handle some weird UI issues on pre-Android-6 -->
<View
android:layout_width="match_parent"
android:layout_height="match_parent"/>


<...CollapsingToolbarLayout
...

当我有坐标布局作为它的视图时,它可能混淆了底部的表格。 我已经更新了项目,但仍然,如果有任何方法有一个更好的解决方案,我想知道它。


最近几个月,Google 发布了自己的 bottomSheet 类,但是我发现它有很多问题,所以我甚至不能尝试它。

你试过这个吗? Http://android-developers.blogspot.in/2016/02/android-support-library-232.html?m=1 这里它说我们可以只指定底部工作表布局行为。

更新:

基本上,连接状态-

通过将 BottomSheetBehavior 附加到坐标布局的子视图(例如,添加 app: layaction = “ android.Support.Design.widget。BottomSheetBehavior”) ,你将自动获得适当的触摸检测来在五个状态之间转换:

STATE_COLLAPSED: this collapsed state is the default and shows just a portion of the layout along the bottom. The height can be controlled with the app:behavior_peekHeight attribute (defaults to 0)
STATE_DRAGGING: the intermediate state while the user is directly dragging the bottom sheet up or down
STATE_SETTLING: that brief time between when the View is released and settling into its final position
STATE_EXPANDED: the fully expanded state of the bottom sheet, where either the whole bottom sheet is visible (if its height is less than the containing CoordinatorLayout) or the entire CoordinatorLayout is filled
STATE_HIDDEN: disabled by default (and enabled with the app:behavior_hideable attribute), enabling this allows users to swipe down on the bottom sheet to completely hide the bottom sheet
Keep in mind that scrolling containers in your bottom sheet must support nested scrolling (for example, NestedScrollView, RecyclerView, or ListView/ScrollView on API 21+).

如果希望接收状态更改的回调,可以添加 BottomSheetCallback:

// The View with the BottomSheetBehavior
View bottomSheet = coordinatorLayout.findViewById(R.id.bottom_sheet);
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
behavior.setBottomSheetCallback(new BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
// React to state change
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
// React to dragging events
}
});

虽然 BottomSheetBehavior 捕获了持久的底层工作表用例,但是这个版本也提供了 BottomSheetDialog 和 BottomSheetDialogFragment 来填充模态底层工作表用例。只需将 AppCompatDialog 或 AppCompatDialogFragment 替换为它们的底部工作表,就可以将您的对话框设置为底部工作表的样式。

最新消息

Because there were like 4 or 5 questions about the same topic, BUT with DIFFERENT requirements, and I tried to answer all of them, but a non-polite admin deleted/closed them, making me create a ticket for each one and changing them to avoid "copy-paste" I will let you a link to the 完整答案 in where you can find all the explanation about how to get full behavior like Google Maps.


回答你的问题

如何模仿谷歌地图的底部表3阶段的行为?

支持库23.x。X + 可以通过修改默认的 BottomSheetBehavior来实现,再添加一个统计数据,步骤如下: < br > < br >

  1. 创建一个 Java 类并从 CoordinatorLayout.Behavior<V>扩展它

  2. 将粘贴代码从默认的 BottomSheetBehavior 文件复制到新文件中。

  3. 用以下代码修改方法 clampViewPositionVertical:

    @Override
    public int clampViewPositionVertical(View child, int top, int dy) {
    return constrain(top, mMinOffset, mHideable ? mParentHeight : mMaxOffset);
    }
    int constrain(int amount, int low, int high) {
    return amount < low ? low : (amount > high ? high : amount);
    }
    
  4. 新增一个州:

    public static final int STATE_ANCHOR_POINT = X;
    
  5. 修改下一个方法: onLayoutChildonStopNestedScrollBottomSheetBehavior<V> from(V view)setState(可选)

我将添加这些修改过的方法和一个 链接到示例项目

下面是它看起来的样子
CustomBottomSheetBehavior

我还必须实现一个类似于谷歌地图显示搜索结果底部表格的视图。

我的看起来是这样的:

Peek view

Expand view scrolled to top

Expand view scrolled to bottom

起初,我定义了一个底部工作表,其中包含一个头部和可滚动内容,但是尽管指定了 wrap_content,lay_ height 似乎既没有包装头部内容,也没有包装可滚动内容。

当我使用 LinearLayout而不是 ConstraintLayout作为 CoordinatorLayout的子布局(以及它的子布局)时,这个问题就消失了。

Activity _ main. xml

<?xml version="1.0" encoding="utf-8"?>
<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"
tools:context=".MainActivity">


<Button
android:id="@+id/buttonPeek"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Peek"
app:layout_constraintEnd_toStartOf="@+id/buttonExpand"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />


<Button
android:id="@+id/buttonExpand"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Expand"
app:layout_constraintEnd_toStartOf="@+id/buttonClose"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/buttonPeek"
app:layout_constraintTop_toTopOf="@+id/buttonPeek" />


<Button
android:id="@+id/buttonClose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Close"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/buttonExpand"
app:layout_constraintTop_toTopOf="@+id/buttonExpand" />


<androidx.coordinatorlayout.widget.CoordinatorLayout 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:id="@+id/layout_coordinator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">


<LinearLayout
android:id="@+id/layout_coordinator_child"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:behavior_hideable="true"
app:layout_behavior="@string/bottom_sheet_behavior">


<LinearLayout
android:id="@+id/layout_bottom_sheet_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFFF0000"
android:orientation="vertical" >


<TextView
android:id="@+id/headerTextView_a"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="a" />


<TextView
android:id="@+id/headerTextView_b"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="b" />


<TextView
android:id="@+id/headerTextView_c"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="c" />


<TextView
android:id="@+id/headerTextView_d"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="d" />


<TextView
android:id="@+id/headerTextView_e"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="e" />


<TextView
android:id="@+id/headerTextView_f"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="f" />


<TextView
android:id="@+id/headerTextView_g"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="g" />


<TextView
android:id="@+id/headerTextView_h"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="h" />


<TextView
android:id="@+id/headerTextView_i"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="i" />


<TextView
android:id="@+id/headerTextView_j"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="j" />


<TextView
android:id="@+id/headerTextView_k"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="k" />


</LinearLayout>


<androidx.core.widget.NestedScrollView
android:id="@+id/layout_bottom_sheet_scrollable_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FF00FF00"
android:fillViewport="true" >


<LinearLayout
android:id="@+id/layout_bottom_sheet_scrollable_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">


<TextView
android:id="@+id/textView0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0" />


<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1" />


<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2" />


<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3" />


<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="4" />


<TextView
android:id="@+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="5" />


<TextView
android:id="@+id/textView6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="6" />


<TextView
android:id="@+id/textView7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="7" />


<TextView
android:id="@+id/textView8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="8" />


<TextView
android:id="@+id/textView9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="9" />


<TextView
android:id="@+id/textView10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="10" />


<TextView
android:id="@+id/textView11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="11" />


<TextView
android:id="@+id/textView12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="12" />


<TextView
android:id="@+id/textView13"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="13" />


<TextView
android:id="@+id/textView14"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="14" />


<TextView
android:id="@+id/textView15"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="15" />


<TextView
android:id="@+id/textView16"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="16" />


<TextView
android:id="@+id/textView17"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="17" />


<TextView
android:id="@+id/textView18"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="18" />


<TextView
android:id="@+id/textView19"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="19" />


<TextView
android:id="@+id/textView20"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="20" />


<TextView
android:id="@+id/textView21"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="21" />


<TextView
android:id="@+id/textView22"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="22" />


<TextView
android:id="@+id/textView23"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="23" />


<TextView
android:id="@+id/textView24"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="24" />


<TextView
android:id="@+id/textView25"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="25" />


<TextView
android:id="@+id/textView26"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="26" />


<TextView
android:id="@+id/textView27"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="27" />


<TextView
android:id="@+id/textView28"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="28" />


<TextView
android:id="@+id/textView29"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="29" />


<TextView
android:id="@+id/textView30"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="30" />


<TextView
android:id="@+id/textView31"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="31" />


<TextView
android:id="@+id/textView32"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="32" />


<TextView
android:id="@+id/textView33"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="33" />


<TextView
android:id="@+id/textView34"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="34" />


<TextView
android:id="@+id/textView35"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="35" />


<TextView
android:id="@+id/textView36"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="36" />


<TextView
android:id="@+id/textView37"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="37" />


<TextView
android:id="@+id/textView38"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="38" />


<TextView
android:id="@+id/textView39"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="39" />


<TextView
android:id="@+id/textView40"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="40" />


<TextView
android:id="@+id/textView41"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="41" />


<TextView
android:id="@+id/textView42"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="42" />


<TextView
android:id="@+id/textView43"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="43" />


<TextView
android:id="@+id/textView44"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="44" />


<TextView
android:id="@+id/textView45"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="45" />


<TextView
android:id="@+id/textView46"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="46" />


<TextView
android:id="@+id/textView47"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="47" />


<TextView
android:id="@+id/textView48"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="48" />


<TextView
android:id="@+id/textView49"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="49" />


</LinearLayout>


</androidx.core.widget.NestedScrollView>
</LinearLayout>


</androidx.coordinatorlayout.widget.CoordinatorLayout>


</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity.java

package com.example.bottomsheetwithscrollablecontent;


import android.os.Bundle;
import android.view.View;
import android.widget.Button;


import com.google.android.material.bottomsheet.BottomSheetBehavior;


import androidx.appcompat.app.AppCompatActivity;
import androidx.coordinatorlayout.widget.CoordinatorLayout;


public class MainActivity extends AppCompatActivity {
private CoordinatorLayout layout_coordinator;
private View layout_coordinator_child;
private View layout_bottom_sheet_header;


private BottomSheetBehavior behavior;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


layout_coordinator = findViewById(R.id.layout_coordinator);
layout_coordinator_child = layout_coordinator.findViewById(R.id.layout_coordinator_child);
layout_bottom_sheet_header = layout_coordinator.findViewById(R.id.layout_bottom_sheet_header);


behavior = BottomSheetBehavior.from(layout_coordinator_child);


Button buttonPeek = findViewById(R.id.buttonPeek);
buttonPeek.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
behavior.setPeekHeight(layout_bottom_sheet_header.getHeight());
behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
});


Button buttonExpand = findViewById(R.id.buttonExpand);
buttonExpand.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
});


Button buttonClose = findViewById(R.id.buttonClose);
buttonClose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
behavior.setState(BottomSheetBehavior.STATE_HIDDEN);
}
});
}
}

App/build.gradle

apply plugin: 'com.android.application'


android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.bottomsheetwithscrollablecontent"
minSdkVersion 24
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}


dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.0-beta01'
implementation 'androidx.constraintlayout:constraintlayout:1.1.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'
implementation 'androidx.legacy:legacy-support-v4:1.0.0-beta01'
implementation "com.google.android.material:material:1.1.0-alpha04"
}