Android BottomSheet效果的两种实现方式
作者:JackMeGo 发布时间:2022-10-14 02:26:23
本文介绍了Android BottomSheet效果的两种实现方式,分享给大家,具体如下:
BottomSheet效果
BottomSheet的效果是指从屏幕底部向上滑的效果,是MaterialDesign风格的一种,视觉效果如下:
BottomSheet效果
实现这种效果有几种不同的方式,如果是在一个固定的页面上添加这种效果,可以在该页面布局中添加BoottomSheet相关的控件。如果是作为通用控件来提供给不同页面使用,则可以使用BottomSheetDialog实现,本文将对两种方法进行讲解,其中会讲到一些使用上的细节,处理不好这些细节,会出现非常怪异的效果。
单页面添加BottomSheet效果
首先引入依赖包:
compile 'com.android.support:design:27.1.1'
页面布局如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/customActionWebView"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="文本一"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="文本二"/>
</LinearLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/nested_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:behavior_hideable="true"
app:behavior_peekHeight="150dp"
android:layout_gravity="bottom"
app:layout_behavior="@string/bottom_sheet_behavior">
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</WebView>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
根布局需要使用CoordinatorLayout,同时在其直接子布局——这里是NestedScrollView——里添加behavior app:layout_behavior = "@string/bottom_sheet_behavior" 。很多文章说指定behavior的控件必须是NestedScrollView,这是错误的,实际上任何view或viewgroup都可以。该behavior配合CoordinateLayout就可以实现behavior所在控件的上滑效果。如果需要上滑的布局展示的时候先漏出一部分,如上面视频所示,可以通过设置 app:behavior_peekHeight 实现,它用来指定漏出的高度。
在代码部分,首先获取NestedScrollView的behavior,然后通过behavior控制底部卡片什么时候弹出,同时会有一些状态回调函数可供调用。
public class BrowserActivity extends AppCompatActivity {
private NestedScrollView nestedScrollView;
private BottomSheetBehavior behavior;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.browser_layout);
nestedScrollView = (NestedScrollView) findViewById(R.id.nested_scroll_view);
behavior = BottomSheetBehavior.from(nestedScrollView);
behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
//这里是bottomSheet 状态的改变
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
//这里是拖拽中的回调,根据slideOffset可以做一些动画
}
});
}
public void showBottomSheet() {
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
}
通过这种方式可以在特定的页面添加底部上滑的效果。
BottomSheetDialog实现通用效果
BottomSheetDialog是BottomSheet效果实现的一种更加通用的方法,比如我们需要在不同的页面实现长按文本弹出卡片列表效果,下面给出实现。
我们集成BottomSheetDialog实现自定义的Dialog,其布局如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView 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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<view class="com.example.trio.tensordemo.CustomBottomSheetDialogForWebView$NestViewEmbeddedListView"
android:id="@+id/card_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@color/transparent"
android:scrollbars="none"
android:dividerHeight="15dp"
android:layout_margin="20dp">
</view>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
注意,这里最外层布局需要是 NestedScrollView ,而 不能是CoordinateLayout ,因为BottomSheetDialog本身已经有个CoordinateLayout根布局,它会把你的布局文件包裹起来,如果你在自己的布局里把最外层布局写成CoordinateLayout,会导致底部上滑的卡片,在下滑消失后屏幕依旧变暗的问题,这是因为整个布局变成了两个CoordinateLayout嵌套,下滑的时候里面的CoordinateLayout滑出屏幕,但外层的CoordinateLayout仍然在展示。通过查阅BottomSheetDialog源码可以看出,它是这样包裹你的布局文件的:
public class BottomSheetDialog extends AppCompatDialog {
...
@Override
public void setContentView(@LayoutRes int layoutResId) {
super.setContentView(wrapInBottomSheet(layoutResId, null, null));
}
private View wrapInBottomSheet(int layoutResId, View view, ViewGroup.LayoutParams params) {
final FrameLayout container = (FrameLayout) View.inflate(getContext(),
R.layout.design_bottom_sheet_dialog, null);
final CoordinatorLayout coordinator =
(CoordinatorLayout) container.findViewById(R.id.coordinator);
if (layoutResId != 0 && view == null) {
view = getLayoutInflater().inflate(layoutResId, coordinator, false);
}
FrameLayout bottomSheet = (FrameLayout) coordinator.findViewById(R.id.design_bottom_sheet);
mBehavior = BottomSheetBehavior.from(bottomSheet);
mBehavior.setBottomSheetCallback(mBottomSheetCallback);
mBehavior.setHideable(mCancelable);
if (params == null) {
bottomSheet.addView(view);
} else {
bottomSheet.addView(view, params);
}
// We treat the CoordinatorLayout as outside the dialog though it is technically inside
coordinator.findViewById(R.id.touch_outside).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mCancelable && isShowing() && shouldWindowCloseOnTouchOutside()) {
cancel();
}
}
});
...
return container;
}
...
}
所以,BottomSheetDialog本身的布局实际如下:
BottomSheetDialog页面布局
我们可以看到最外层是FrameLayout,里面有个CoordinateLayout,CoordinateLayout里面有个直接子布局FrameLayout,该CoordinateLayout指定了Behavior,最里面才是用户自定义的布局,所以不应该在自定义布局里再添加CoordinateLayout,也不应该再次指定Behavior,直接摆放你的内容就行。
我们的自定义布局如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView 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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<view class="com.example.trio.tensordemo.CustomBottomSheetDialogForWebView$NestViewEmbeddedListView"
android:id="@+id/card_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@color/transparent"
android:scrollbars="none"
android:dividerHeight="15dp"
android:layout_margin="20dp">
</view>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
布局的核心是一个ListView,注意,由于ListView和behavior都需要处理滑动事件,所以直接使用ListView会导致滑动冲突,解决办法是采用ScrollView嵌套ListView实现,同时使用自定义的ListView将所有列表项展开。
自定义的NestViewEmbeddedListView如下:
public static class NestViewEmbeddedListView extends ListView {
public NestViewEmbeddedListView(android.content.Context context, android.util.AttributeSet attrs){
super(context, attrs);
}
/**
* 设置不滚动
*/
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
自定义的BottomSheetDialog代码如下:
public class CustomBottomSheetDialogForWebView extends BottomSheetDialog {
private Context context;
private NestViewEmbeddedListView listView;
private NerResult nerResult;
private CardListAdapter cardListAdapter = new CardListAdapter();
public CustomBottomSheetDialogForWebView(@NonNull Context context, NerResult nerResult) {
super(context);
this.context = context;
this.nerResult = nerResult;
createView();
}
public void createView() {
View bottomSheetView = getLayoutInflater().inflate(R.layout.webview_bottom_sheet_layout, null);
setContentView(bottomSheetView);
// 注意:这里要给layout的parent设置peekHeight,而不是在layout里给layout本身设置,下面设置背景色同理,坑爹!!!
BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(((View) bottomSheetView.getParent()));
bottomSheetBehavior.setPeekHeight(730);
((View) bottomSheetView.getParent()).setBackgroundColor(context.getResources().getColor(R.color.transparent));
listView = bottomSheetView.findViewById(R.id.card_list_view);
cardListAdapter.setNerItems(nerResult);
listView.setAdapter(cardListAdapter);
}
}
这里需要注意的就是,设置背景透明和获取Behavior都是对自定义布局的父布局,也就是bottomSheetView.getParent()进行。最终的效果就是下面的效果:
BottomSheet效果
来源:https://www.jianshu.com/p/ae866a43c8e3


猜你喜欢
- 本文实例讲述了java数据结构与算法之快速排序。分享给大家供大家参考,具体如下:交换类排序的另一个方法,即快速排序。快速排序:改变了冒泡排序
- 下面通过代码给大家分享下依赖注入框架Autofac的使用,具体如下所示: Autofac是一款IOC框架,比较于其他的IOC框架,
- 内发光原理内发光原理简单概况是:采样周边像素alpha取平均值叠加效果。概括来说似乎好像特别简单,但需要一定的理解和消化。发光物体可以当做是
- ButterKnife的最新版本是8.4.0。首先,需要导入ButterKnife的jar包。在AndroidStudio中,File-&g
- Android 自定义 Toast 显示时间实现代码:package com.wm.realname.util;import android
- Spring Boot 默认为我们提供了静态资源处理,使用 WebMvcAutoConfiguration 中的配置各种属性。建议大家使用S
- 对HDFS上的文件进行上传和下载是对集群的基本操作,在《HADOOP权威指南》一书中,对文件的上传和下载都有代码的实例,但是对如何配置HAD
- Spring Security的本质Spring Security 本质上是一连串的 Filter , 然后又以一个独立的 Filter 的
- 好了 我们聊聊 Bean 的实例化过程的几个重要角色BeanDefinitionRegistryPostProcessor 接口Refres
- 前言TensorFlow是Google开源的一款人工智能学习系统。为什么叫这个名字呢?Tensor的意思是张量,代表N维数组;Flow的意思
- Note:这篇文章是基于Android Studio 3.01版本的,NDK是R16。step1:创建一个包含C++的项目其他默认就可以了。
- 在项目迁移到Spring Boot之后,发生内存使用量过高的问题。本文介绍了整个排查过程以及使用到的工具,也非常适用于其他堆外内存排查。背景
- 零、业务逻辑Controller-->service接口-->serviceImpl-->dao接口-->daoIm
- Java 项目中常常回遇到发送邮件Java 发送邮件有几种,今天先给大家介绍用 HtmlEmail 来发送邮件,我这里是用 Maven 来搭
- MD5加密MD5是由MD2、MD3、MD4演变过来的,虽然MD5加密算法现在有些人已经将其解开了,但是它的加密机制依然很强大,我想绝大对数还
- 1. 判断允许上传文件的 文件后缀/图片后缀/相片后缀 和 其它工具类import org.springframework.stereoty
- 本文实例讲述了C#计算字符串哈希值(MD5、SHA)的方法。分享给大家供大家参考。具体如下:一、关于本文本文中是一个类库,包括下面几个函数:
- 一、为什么按值调用和按引用调用?方法或函数可以通过两种方式调用。一种是按值调用,另一种是按引用调用,这两种方式通常根据作为输入或参数传递给它
- 本文实例为大家分享了java实现转圈打印矩阵的具体代码,供大家参考,具体内容如下给定一个整形矩阵Matrix,请按照顺时针方向转圈的方式,输
- 今天看《第一行代码》上面关于拍照和从相册选取图片那一部分,发现始终出不来效果,所以搜索其他资料学习一下相关知识,写一个简单的Demo。&nb