BottomSheet
简介
BottomSheet是指底部弹出的视图。在使用DrawerLayout时可以实现从屏幕左侧和右侧弹出布局,但是不能从底部弹出。因此了解到了BottomSheet。
BottomSheet的具体实现包括:
-
BottomSheetBehavior:一般直接作用在View上,一般在xml布局中直接对view设置属性,轻量级,代码少,灵活行高。适用于复杂页面下的半瓶弹出效果。使用CoordinatorLayout布局和行为属性app:layout_behavior="@string/bottom_sheet_behavior"。
-
BottomSheetDialog:使用方法和对话框的使用基本一致,通过setContentView()设定布局,调用show展示。一般用于底部弹出的对话框或者弹窗。
-
BottomSheetDialogFragment:使用方法和普通的Fragment一样,可以将交互和UI写在Fragment内。
BottomSheet的五个状态
-
STATE_COLLAPSED:折叠状态。一般是半屏状态。可通过app:behavior_peekHeight来设置默认显示的高度。
-
STATE_EXPANDED:完全展开状态。默认是屏幕高度。
-
STATE_HIDDEN:隐藏状态,并不是GONE,而是出于屏幕的最下方,不可见。
-
STATE_DRAGGING:拖拽状态。手指在屏幕上拖动视图(手指未离开屏幕前)。
-
STATE_SETTING:拖拽结束直到到达终点位置(STATE_COLLAPSED或者STATE_EXPANDED)这段时间。
BottomSheetBehavior的使用
BottomSheetBehavior的使用需要借助行为属性app:layout_behavior="@string/bottom_sheet_behavior"。所以一般嵌套在CoordinatorLayout中使用。
<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:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/parent_layout"
tools:context=".MainActivity">
<TextView
android:id="@+id/hello_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:layout_gravity="center" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#479bf7"
//特别指定的属性
app:behavior_hideable="true"
app:behavior_peekHeight="20dp"
app:layout_behavior="@string/bottom_sheet_behavior"
/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
主要就是指定行为属性"@string/bottom_sheet_behavior",和一些相关的属性,没什么特别的。
常用属性:
app:behavior_hideable="false"
//该属性表示该视图是否可以完全隐藏,如果设置为true,该视图在屏幕上完全隐藏,用户也就没法拖拽出来,可以通过监听在代码中调出
app:behavior_peekHeight="20dp"
//最小可见高度,也是折叠时显示在屏幕上的高度
app:behavior_skipCollapsed="true"
//设置为true可以使得底部表单直接从折叠状态跳转到完全展开的状态,而不经过中间的折叠状态
app:behavior_fitToContents="true"
//设置为true表示使用内容高度,和warp_content有相似的效果
其实这时运行代码,一个可以拖拽出来也可以拉回去的底部弹窗就已经完成了。
通常也会这样使用:
布局文件中不用修改其他代码,不过需要将< RecyclerView>的app:behavior_hideable=""属性设为true。
实现点击底部弹窗完全隐藏,点击TextView让它完全展开,再次点击让它完全隐藏。
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
Adapter adapter;
List<Integer> ims = new ArrayList<>();
BottomSheetBehavior bottomSheetBehavior;
TextView hello;
CoordinatorLayout parentLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Collections.addAll(ims, R.drawable.i1, R.drawable.i2, R.drawable.i3, R.drawable.i4,
R.drawable.i5, R.drawable.i6);
recyclerView = (RecyclerView) findViewById(R.id.recycler);
adapter = new Adapter(ims);
recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
recyclerView.setAdapter(adapter);
bottomSheetBehavior = BottomSheetBehavior.from(recyclerView);
//传入拥有行为属性"@string/bottom_sheet_behavior"的视图,获取控制视图底部弹出和收回动作的BottomSheetBehavior对象
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);//默认视图的状态为隐藏
hello = findViewById(R.id.hello_text);
//获取控制底部弹窗的控件,设置监听事件
hello.setOnClickListener(view -> {
Log.d("TAG", "onCreate: " + bottomSheetBehavior.getState());
if (bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_HIDDEN
|| bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_COLLAPSED) {
//如果当前是隐藏的,或者是折叠的 就完全展开
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
} else if (bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED){
//如果是完全展开的 就隐藏
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
}
});
//因为BottomSheetBehavior没有直接提供点击试图外关闭底部弹窗的功能,
// 所以通常获取父布局CoordinatorLayout的实例并设置监听,将底部弹窗关闭
parentLayout = findViewById(R.id.parent_layout);
parentLayout.setOnClickListener(view -> {
if (bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) {
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
}
});
}
}
看看效果。
BottomSheetBehaior的状态监听
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(View bottomSheet, int newState) {
//监听BottomSheet状态的改变
}
@Override
public void onSlide(View bottomSheet, float slideOffset) {
//监听拖拽中的回调,根据slideOffset可以做一些动画
}
});
BottomSheetDialog的使用
基本使用:
我新创建了一个布局,这个布局中只有一个RecyclerView,让它实现和上面一样的效果。布局名叫the_layout。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_vi"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#479bf7"
/>
</LinearLayout>
在MainActivity中编写代码:
public class MainActivity extends AppCompatActivity {
BottomSheetDialog bottomSheetDialog;
TextView hello;
List<Integer> ims = new ArrayList<>();
@SuppressLint({"ResourceType", "MissingInflatedId"})
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
hello = (TextView) findViewById(R.id.hello_text);
Collections.addAll(ims, R.drawable.i1, R.drawable.i2, R.drawable.i3, R.drawable.i4,
R.drawable.i5, R.drawable.i6);
//初始化列表数据
bottomSheetDialog = new BottomSheetDialog(this);
//1.首先初始化底部弹出对话框
bottomSheetDialog.setContentView(R.layout.the_layout);
//2.给底部弹出对话框加载布局
RecyclerView recyclerView = bottomSheetDialog.findViewById(R.id.recycler_vi);
if (recyclerView != null) {
recyclerView.setAdapter(new Adapter(ims));
recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
}
//3.加载页面信息
hello.setOnClickListener(view -> {
Log.d("click", "onCreate: ");
bottomSheetDialog.show();
});
//4.展示
}
}
注意:这里的第三步的加载数据,获取控件时一定要用BottomSheetDialog对象去调用findViewById方法。
常用方法:
bottomSheetDialog.setContentView();//传入R.layout.*或者用LayoutInflater加载的View
bottomSheetDialog.setCanceledOnTouchOutside(boolean cancel);//设置是否与可以点击弹窗以外的区域关闭弹窗,默认true
bottomSheetDialog.show();//显示
bottomSheetDialog.dismiss();//关闭
bottomSheetDialog.setOnShowListener(DialogInterface.OnShowListener listener);//设置对话框显示时的监听器。
bottomSheetDialog.setOnDismissListener(DialogInterface.OnDismissListener listener);//设置对话框关闭时的监听器。
//还可以添加BottomSheetBehavior进行设置
BottomSheetBehavior<View> behavior = BottomSheetBehavior.from(view);//传入的是与BottomSheetDialog相关的控件,视图
// 设置最小高度
behavior.setPeekHeight(500);
在构造函数中可以指定自定义主题进行优化显示
使用shape约束圆角。
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#479bf7"/>
<corners android:topLeftRadius="10dp"
android:topRightRadius="10dp"/>
<stroke android:color="@color/black"
android:width=".1dp"
/>
</shape>
将这个shape用android:background属性应用到布局文件中就行了。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ss"
>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_vi"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
如果更改BottomSheetDialog的主题可以在构造函数中指定。
bottomSheetDialog = new BottomSheetDialog(this, R.style.BottomSheetDialogTheme);
BottomSheetDialogFragment的使用
BottomSheetDialog的两种用法:
用法一:
重写BottomSheetDialogFragment中的OnCreateDialog方法。
public class BSFragment extends BottomSheetDialogFragment {
private List<Integer> ims = new ArrayList<>();
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);
View view = View.inflate(getContext(), R.layout.the_layout, null);
Collections.addAll(ims, R.drawable.i1, R.drawable.i2, R.drawable.i3, R.drawable.i4,
R.drawable.i5, R.drawable.i6);
bottomSheetDialog.setContentView(view);
RecyclerView recyclerView = bottomSheetDialog.findViewById(R.id.recycler_vi);
if (recyclerView != null) {
recyclerView.setAdapter(new Adapter(ims));
recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 3));
}
return bottomSheetDialog;
}
}
在onCreateDialog方法中创建BottonSheetDialog进行显示。
在MainActivity中
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView hello = findViewById(R.id.hello_text);
hello.setOnClickListener(view -> {
BSFragment fragment = new BSFragment();
fragment.show(getSupportFragmentManager(), "1");
});
}
获取到Fragment类的实例后调用show()方法进行显示,第一个参数获取supportFragmentManager,第二个参数是Tag。
BottomSheet详解 - 掘金 (juejin.cn)
BottomSheet 的使用介绍(BottomSheetBeahvior,BottomSheetDialog,BottomSheetDialogFragment)-CSDN博客