android BottomSheetDialog新控件解析实现知乎评论列表效果(实例代码)
BottomSheetDialog使用解析
Android Support Library 23.2里的 Design Support Library新加了一个Bottom Sheets控件,Bottom Sheets顾名思义就是底部操作控件,用于在屏幕底部创建一个可滑动关闭的视图,可以替代对话框和菜单。其中包含BottomSheets、BottomSheetDialog和BottomSheetDialogFragment三种可以使用。其中应用较多的控件是BottomSheetDialog,主要运用在界面底部分享列表,评论列表等,最近在知乎评论列表界面看到知乎运用到了这个效果,所有在这里详细介绍一下该控件的使用,以及简单实现知乎评论列表功能。本文实现效果如下:
首先我们想要使用BottomSheets相关控件,需要先在build.gradle中添加design依赖,本文中使用的是:
compile ‘com.android.support:design:25.3.0’
BottomSheetDialog可以替代大多数网格显示和列表展示的dialog和popupwindow,默认宽度撑满,并且在BottomSheetDialog 区域中向下滑动也让对话框消失。
接下来创建BottomSheetDialog的布局文件dialog_bottomsheet.xml,布局文件如下:
<?xml version="1.0" encoding="utf-8"?
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
<RelativeLayout
android:id="@+id/dialog_bottomsheet_rl_title"
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="@drawable/dialog_bottomsheet_shape"
<ImageView
android:id="@+id/dialog_bottomsheet_iv_close"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_centerVertical="true"
android:layout_marginLeft="5dp"
android:padding="5dp"
android:src="@drawable/img_close" /
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/dialog_bottomsheet_iv_close"
android:text="评论"
android:textColor="#333"
android:textSize="16sp" /
</RelativeLayout
<android.support.v7.widget.RecyclerView
android:id="@+id/dialog_bottomsheet_rv_lists"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/dialog_bottomsheet_rl_title"
android:background="#fff" /
</RelativeLayout
布局文件中,主要包含一个RecyclerView和一个头布局。
然后,我们在Activity界面添加BottomSheetDailog初始化方法,
private void showSheetDialog() {
View view = View.inflate(BottomSheetDialogActivity.this, R.layout.dialog_bottomsheet, null);
iv_dialog_close = (ImageView) view.findViewById(R.id.dialog_bottomsheet_iv_close);
rv_dialog_lists = (RecyclerView) view.findViewById(R.id.dialog_bottomsheet_rv_lists);
iv_dialog_close.setOnClickListener(this);
bottomSheetAdapter = new BottomSheetAdapter(BottomSheetDialogActivity.this, list_strs);
rv_dialog_lists.setHasFixedSize(true);
rv_dialog_lists.setLayoutManager(new LinearLayoutManager(BottomSheetDialogActivity.this));
rv_dialog_lists.setItemAnimator(new DefaultItemAnimator());
rv_dialog_lists.setAdapter(bottomSheetAdapter);
bottomSheetDialog = new BottomSheetDialog(BottomSheetDialogActivity.this, R.style.dialog);
bottomSheetDialog.setContentView(view);
}
在改方法中,我们首先获取BottomSheetDialog的布局文件,获取该布局文件中相关控件,通过创建模拟列表数据,为RecyclerView添加适配器
for (int i=0; i<20; i++) {
list_strs.add("评论" + i);
}
通过如下代码,创建BottomSheetDialog对象
bottomSheetDialog = new BottomSheetDialog(BottomSheetDialogActivity.this, R.style.dialog);
bottomSheetDialog.setContentView(view);
至此,我们即可以通过调用
bottomSheetDialog.show();
方法来查看BottomSheetDialog显示效果
使用过程中出现的问题
当我们向下滑动BottomSheetDialog隐藏Dialog后,无法用bottomSheetDialog.show()再次打开,为什么呢?我们先看下源码的实现:
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
super.setContentView(wrapInBottomSheet(0, view, params));
}
private View wrapInBottomSheet(int layoutResId, View view, ViewGroup.LayoutParams params) {
final CoordinatorLayout coordinator = View.inflate(getContext(),R.layout...., null);
FrameLayout bottomSheet = (FrameLayout) coordinator.findViewById(R.id.design_bottom_sheet);
BottomSheetBehavior.from(bottomSheet).setBottomSheetCallback(mBottomSheetCallback);
...
return coordinator;
}
private BottomSheetCallback mBottomSheetCallback = new BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
dismiss(); //关键代码
}
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
}
};
通过源码文件我们可以看出,系统的BottomSheetDialog是基于BottomSheetBehavior封装的,当我们滑动隐藏了BottomSheetBehavior中的View后,内部是设置了BottomSheetBehavior的状态为STATE_HIDDEN,接着它替我们关闭了Dialog,所以我们再次调用show()的时候Dialog没法再此打开状态为HIDE的Dialog了。 查看了源文件,我们就通过复写BottomSheetCallback的回调方法,来实现我们的效果,这里就引入了BottomSheetBehavior,下面先介绍BottomSheetBehavior的使用。
BottomSheetBehavior的作用
根据官方Api,BottomSheetBehavior有一个静态方法BottomSheetBehavior.from(View),会返回这个View引用的BottomSheetBehavior,这个方法会检查这个View是否是CoordinatorLayout的子View,如果是就会得到这个View的Behavior。通过BottomSheetBehavior,我们可以通过setPeekHeight(int height)设置dialog的显示高度,通过setBottomSheetCallback(callback)实现BottomSheetDialog的状态监听。其中,在BottomSheetCallback回调方法中,onStateChanged监听状态的改变,onSlide是拖拽的回调,onStateChanged可以监听到的回调一共有五种:
- STATE_HIDDEN: 隐藏状态。默认是false,可通过app:behavior_hideable属性设置。
- STATE_COLLAPSED: 折叠关闭状态。可通过app:behavior_peekHeight来设置显示的高度,peekHeight默认是0。
- STATE_DRAGGING: 被拖拽状态
- STATE_SETTLING: 拖拽松开之后到达终点位置(collapsed or expanded)前的状态。
- STATE_EXPANDED: 完全展开的状态。
那么如何获取到BottomSheetDialog的BottomSheetBehavior呢?
第一种:在BottomSheetDialog调用setContentView方法之后,调用
BottomSheetBehavior mDialogBehavior = BottomSheetBehavior.from((View) mContentView.getParent());
第二种:在BottomSheetDialog调用setContentView方法之后,调用
final FrameLayout frameLayout = (FrameLayout) dialog.findViewById(android.support.design.R.id.design_bottom_sheet);
frameLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
frameLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
BottomSheetBehavior behavior = BottomSheetBehavior.from(frameLayout);
//调用behavior相关方法
...
frameLayout.forceLayout();
}
通过上面的介绍,修改上文中的showSheetDialog()用于解决上文中出现的问题,代码如下:
private void showSheetDialog() {
View view = View.inflate(BottomSheetDialogActivity.this, R.layout.dialog_bottomsheet, null);
iv_dialog_close = (ImageView) view.findViewById(R.id.dialog_bottomsheet_iv_close);
rv_dialog_lists = (RecyclerView) view.findViewById(R.id.dialog_bottomsheet_rv_lists);
iv_dialog_close.setOnClickListener(this);
bottomSheetAdapter = new BottomSheetAdapter(BottomSheetDialogActivity.this, list_strs);
rv_dialog_lists.setHasFixedSize(true);
rv_dialog_lists.setLayoutManager(new LinearLayoutManager(BottomSheetDialogActivity.this));
rv_dialog_lists.setItemAnimator(new DefaultItemAnimator());
rv_dialog_lists.setAdapter(bottomSheetAdapter);
bottomSheetDialog = new BottomSheetDialog(BottomSheetDialogActivity.this, R.style.dialog);
bottomSheetDialog.setContentView(view);
mDialogBehavior = BottomSheetBehavior.from((View) view.getParent());
mDialogBehavior.setPeekHeight(getWindowHeight());
mDialogBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
bottomSheetDialog.dismiss();
mDialogBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
}
});
}
在监听到用户滑动关闭BottomSheetDialog后,我们把BottomSheetBehavior的状态设置为BottomSheetBehavior.STATE_COLLAPSED,也就是半个打开状态(BottomSheetBehavior.STATE_EXPANDED为全打开),至此就解决了调用show()方法无法正常打开的问题。同时我们通过设置setPeekHeight和BottomSheetDialog的透明主题来实现知乎评论列表的效果。 在values/styles.xml文件中添加透明主题
<style name="dialog" parent="@android:style/Theme.Dialog"
<item name="android:windowFrame" @null</item
<item name="android:windowIsFloating" true</item
<item name="android:windowIsTranslucent" true</item
<item name="android:windowNoTitle" true</item
<item name="android:background" @android:color/transparent</item
<item name="android:windowBackground" @android:color/transparent</item
<item name="android:backgroundDimEnabled" true</item
<item name="android:backgroundDimAmount" 0.6</item
</style
最后附上Activity界面完整代码如下:
public class BottomSheetDialogActivity extends AppCompatActivity implements View.OnClickListener {
private Button bt_start;
private ImageView iv_dialog_close;
private RecyclerView rv_dialog_lists;
private BottomSheetAdapter bottomSheetAdapter;
private BottomSheetDialog bottomSheetDialog;
private BottomSheetBehavior mDialogBehavior;
private List<String list_strs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bottom_sheet_dialog);
list_strs = new ArrayList< ();
initView();
showSheetDialog();
}
private void initView() {
bt_start = (Button) findViewById(R.id.main_bt_start);
for (int i=0; i<20; i++) {
list_strs.add("评论" + i);
}
bt_start.setOnClickListener(this);
}
private void showSheetDialog() {
View view = View.inflate(BottomSheetDialogActivity.this, R.layout.dialog_bottomsheet, null);
iv_dialog_close = (ImageView) view.findViewById(R.id.dialog_bottomsheet_iv_close);
rv_dialog_lists = (RecyclerView) view.findViewById(R.id.dialog_bottomsheet_rv_lists);
iv_dialog_close.setOnClickListener(this);
bottomSheetAdapter = new BottomSheetAdapter(BottomSheetDialogActivity.this, list_strs);
rv_dialog_lists.setHasFixedSize(true);
rv_dialog_lists.setLayoutManager(new LinearLayoutManager(BottomSheetDialogActivity.this));
rv_dialog_lists.setItemAnimator(new DefaultItemAnimator());
rv_dialog_lists.setAdapter(bottomSheetAdapter);
bottomSheetDialog = new BottomSheetDialog(BottomSheetDialogActivity.this, R.style.dialog);
bottomSheetDialog.setContentView(view);
mDialogBehavior = BottomSheetBehavior.from((View) view.getParent());
mDialogBehavior.setPeekHeight(getWindowHeight());
mDialogBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
bottomSheetDialog.dismiss();
mDialogBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
}
});
}
private int getWindowHeight() {
Resources res = BottomSheetDialogActivity.this.getResources();
DisplayMetrics displayMetrics = res.getDisplayMetrics();
return displayMetrics.heightPixels;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.main_bt_start:
if (bottomSheetDialog != null) {
bottomSheetDialog.show();
}
break;
case R.id.dialog_bottomsheet_iv_close:
if (bottomSheetDialog != null) {
bottomSheetDialog.dismiss();
}
break;
}
}
}
到此这篇关于android BottomSheetDialog新控件解析实现知乎评论列表效果的文章就介绍到这了,更多相关android 知乎评论列表内容请搜索ZaLou.Cn以前的文章或继续浏览下面的相关文章希望大家以后多多支持ZaLou.Cn!
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- html+css实现彩色渐变滑动条
- 项目实战 01:将唐诗三百首写入 Elasticsearch 会发生什么?
- 装饰器和代理模式的区别,从一碗小米粥谈起
- EasyNVR部署在centos虚拟机上出现无法访问情况,该如何排查?
- RTSP协议网页无插件直播平台EasyNVR视频广场无法搜索纯数字关键词的通道,该如何解决的?
- RTSP协议网页无插件直播平台EasyNVR通道管理搜索纯数字关键词,返回结果为空如何解决?
- Mysql如何选择唯一索引和普通索引
- Python自学成才之路 多线程开发
- Mysql为什么会抖一下呢
- Python自学成才之路 线程间协作 lock,condition,event的使用
- Java 语言基础 (初识Java语言, 变量和数据类型, 运算符, 流程控制语句, 数组)
- python自学成才之路 线程间协作之Semaphore,threading.local()
- jenkins基础
- Java 语言基础 (类和对象, 方法和封装, static 关键字和继承, 多态和特殊类)
- 安防视频监控系统视频上云解决方案EasyCVR集成海康EHome私有协议系列:设备录像流数据进行PS包分割