版权声明:转载必须注明本文转自严振杰的博客: http://blog.csdn.net/yanzhenjie1003

今天的效果在支付宝、淘宝、京东等电商App中很常见。比如支付宝输入密码弹窗、商城下单时选择商品属性时,从下面浮动上来一个PopupWindow,那么今天就带大家用Behavior来实现这两个效果,结果你会发现简直只需要一行代码。

总结下现在用的APP:
1. 仿支付宝弹出的输入支付密码窗口。
2. 仿淘宝/天猫弹出商品属性选择框。
3. 知乎首页上下滑动隐藏ToolBar和NavigationBar。
4. …

系列博客:
1. Material Design系列,Behavior之BottomSheetBehavior与BottomSheetDialog
2. Material Design系列,Behavior之SwipeDismissBehavior
3. Material Design系列,自定义Behavior之上滑显示返回顶部按钮
4. Material Design系列,自定义Behavior实现Android知乎首页
5. Material Design系列,自定义Behavior支持所有 View

效果预览

源码下载:http://download.csdn.net/detail/yanzhenjie1003/9578770,推荐先阅读博客理解原理。

引文

在我的技术群里有小伙伴们讨论Behavior,我也去玩了玩,我也对Behavior写了系列博客。选中Behavior然后ctrol + t后发现Behavior的一个实现类:BottomSheetBehavior,我就到Android官网上翻了下资料,一翻就发现了惊喜啊,下面就把这些惊喜介绍给大家。

更多文章请Google/百度搜索我名字:严振杰,排名第一的就是我。

BottomSheetBehavior怎么玩(知乎Bottom隐藏和显示)

玩这个东西,首先Behavior作为CoordinatorLayout的子View的LayoutParams(原因看后文解释),所以CoordinatorLayout是万万不能少的,先来亮出整个布局:

<android.support.design.widget.CoordinatorLayout 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: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"app:popupTheme="@style/AppTheme.PopupOverlay" /></android.support.design.widget.AppBarLayout><LinearLayout
        android:layout_width="match_parent"android:layout_height="match_parent"android:layout_above="@+id/tab_layout"android:gravity="center"android:orientation="vertical"app:layout_behavior="@string/appbar_scrolling_view_behavior"><Button
            android:id="@+id/btn_bottom_sheet_control"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="sheet 显示/隐藏" /></LinearLayout><LinearLayout
        android:id="@+id/tab_layout"android:layout_width="match_parent"android:layout_height="?actionBarSize"android:layout_alignParentBottom="true"android:background="@android:color/holo_purple"app:layout_behavior="@string/bottom_sheet_behavior"><Button
            android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:text="第一" /><Button
            android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:text="第二" /><Button
            android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:text="第三" /><Button
            android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:text="第四" /></LinearLayout></android.support.design.widget.CoordinatorLayout>

大概介绍下,页面上只能看到Toolbar和一个Buttonsheet 显示/隐藏,然后android:id="@+id/tab_layout"这个布局是横向的,给它设置了Behaviorapp:layout_behavior="@string/bottom_sheet_behavior",经过测试发现,如果不给tab_layout设置BottomSheetBehavior,它会浮动在整个页面的顶部,并在Toolbar的下面。设置了BottomSheetBehavior它会被BottomSheetBehavior自动移动到页面底部外边,所以在页面上是看不到android:id="@+id/tab_layout"这个布局的。

页面画好了,难道它会自动开关吗,怎么去控制它的打开和关闭呢?那么我们就来看看这货的真实面貌,经过我看Android的官方api发现,BottomSheetBehavior这个货有一个静态方法BottomSheetBehavior.from(View),会返回这个View引用的BottomSheetBehavior

public static <V extends View> BottomSheetBehavior<V> from(V view) {ViewGroup.LayoutParams params = view.getLayoutParams();if (!(params instanceof CoordinatorLayout.LayoutParams)) {throw new Exception("The view is not a child of CoordinatorLayout");}CoordinatorLayout.Behavior behavior = params.getBehavior();if (!(behavior instanceof BottomSheetBehavior)) {throw new IllegalArgumentException("...");}return (BottomSheetBehavior<V>) behavior;
}

这个方法会检查这个View是否是CoordinatorLayout的子View,如果是才会去拿到这个View的Behavior,所以诸位也应该明白为什么我开头说Behavior作为CoordinatorLayout子View的LayoutParams了。

接下来我们看看拿到这个货后怎么用:

private BottomSheetBehavior mBottomSheetBehavior;@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.bsbehavior_activity);Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);setSupportActionBar(toolbar);getSupportActionBar().setDisplayHomeAsUpEnabled(true);findViewById(R.id.btn_bottom_sheet_control).setOnClickListener(onClickListener);// 拿到这个tab_layout对应的BottomSheetBehaviormBottomSheetBehavior = BottomSheetBehavior.from(findViewById(R.id.tab_layout));
}

findViewById(R.id.btn_bottom_sheet_control).setOnClickListener(onClickListener);是给刚才说的页面中的Button设置了监听,我们用这个按钮来控制tab_layout的显示和隐藏。

我发现有一个方法可以获取到它所依附的View此时的状态:mBottomSheetBehavior.getState(),翻阅了源码后发现它的返回值有以下几种:

/*** The bottom sheet is dragging.*/
public static final int STATE_DRAGGING = 1;/*** The bottom sheet is settling.*/
public static final int STATE_SETTLING = 2;/*** The bottom sheet is expanded.*/
public static final int STATE_EXPANDED = 3;/*** The bottom sheet is collapsed.*/
public static final int STATE_COLLAPSED = 4;/*** The bottom sheet is hidden.*/
public static final int STATE_HIDDEN = 5;

当我看到STATE_EXPANDEDSTATE_COLLAPSED就明白了它的用法了,不就是展开和隐藏起来了麽?所以我们判断这个状态,如果是隐藏就显示,如果是显示就隐藏:

@Override
public void onClick(View v) {if (v.getId() == R.id.btn_bottom_sheet_control) {if (mBottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) {mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);} else if (mBottomSheetBehavior.getState() == BottomSheetBehavior.STATE_COLLAPSED) {mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);}}
}

到这里,知乎首页的Bottom的隐藏和显示也就讲玩了,接下来我们来看看支付宝淘宝的下方弹窗如何实现。

BottomSheetDialog怎么玩(商城下单商品属性选择弹窗)

这个类的发现也是在Android官网搜索BottomSheetBehavior时发现的,一看到BottomSheetDialog后心中狂喜,后来经过我验证,它显示的效果和我猜想的一模一样啊,既然是个Dialog,那么用法应该和普通Dialog没啥去区别了吧。

然后我就顺势new了一个BottomSheetDialog

private BottomSheetDialog mBottomSheetDialog;@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);...createBottomSheetDialog();
}private void createBottomSheetDialog() {mBottomSheetDialog = new BottomSheetDialog(this);View view = LayoutInflater.from(this).inflate(R.layout.dialog_bottom_sheet, null, false);mBottomSheetDialog.setContentView(view);RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);...recyclerView.setAdapter(adapter);
}

View里面是一个RecyclerView

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/recyclerView"android:layout_width="match_parent"android:layout_height="match_parent" />

然后用下面的代码去控制它的显示和隐藏。

if (mBottomSheetDialog.isShowing()) {mBottomSheetDialog.dismiss();
} else {mBottomSheetDialog.show();
}

当这个Dialog Show出来的时候发现它显示了一半,嗯这个效果确实不错,这样就达到了我们最初说的支付宝密码弹窗和淘宝/天猫商品属性选择。我们滑动的时候如果下面有内容它就会EXPANDED,如果是一个普通的View(非RecyclerView、NestedScrollView)将不会继续往上滑动,下面的内容会继续跟着出来,但是同样可以向下滑动隐藏,也可以调用dismissclose关闭。

BottomSheetDialog的神坑

作为一个有情怀的程序员,这里把我踩过的坑和解决方案跟大家分享一下。

我发现当这个Dilaog打开再关闭后,无法用Dialog.show()再次打开,为什么呢?

我去阅读了一下BottomSheetDialog源代码,发现了如下代码:

 @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() {@Overridepublic void onStateChanged(@NonNull View bottomSheet, int newState) {if (newState == BottomSheetBehavior.STATE_HIDDEN) {dismiss();}}@Overridepublic void onSlide(@NonNull View bottomSheet, float slideOffset) {}
};

也就是说,系统的BottomSheetDialog是基于BottomSheetBehavior封装的,这里判断了当我们滑动隐藏了BottomSheetBehavior中的View后,内部是设置了BottomSheetBehavior的状态为STATE_HIDDEN,接着它替我们关闭了Dialog,所以我们再次调用dialog.show()的时候Dialog没法再此打开状态为HIDE的dialog了。

这里就有个疑问了:
Google为啥没有提供我们自己设置BottomSheetCallback的接口呢?

没有关系,看了源码发现很简单,我们自己来实现,并且在监听到用户滑动关闭BottomSheetDialog后,我们把BottomSheetBehavior的状态设置为BottomSheetBehavior.STATE_COLLAPSED,也就是半个打开状态(BottomSheetBehavior.STATE_EXPANDED为全打开),根据源码我把设置的方法提供下:

private void setBehaviorCallback() {View view = mBottomSheetDialog.getDelegate().findViewById(android.support.design.R.id.design_bottom_sheet);final BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(view);bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {@Overridepublic void onStateChanged(@NonNull View bottomSheet, int newState) {if (newState == BottomSheetBehavior.STATE_HIDDEN) {mBottomSheetDialog.dismiss();bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);}}@Overridepublic void onSlide(@NonNull View bottomSheet, float slideOffset) {}});
}

这样就解决了BottomSheetDialog关闭后不能再次打开的问题了。

2016.12.11更新:我的代码发现用的是23的,如果是用的是24或者以上的话要在xml中加app:behavior_hideable=”true”的属性,sheet的隐藏和显示也要用STATE_EXPANDED 和 STATE_HIDDEN这两个状态,这一点感谢狂爱柚子茶同学的反馈。

源码下载:http://download.csdn.net/detail/yanzhenjie1003/9578770

版权声明:转载必须注明本文转自严振杰的博客: http://blog.csdn.net/yanzhenjie1003

Material之Behavior实现支付宝密码弹窗 仿淘宝/天猫商品属性选择相关推荐

  1. 基于BootStrap仿淘宝星星商品评价案例

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8" ...

  2. 仿淘宝天猫双11下拉倒计时领取豆子

    仿淘宝天猫双11下拉倒计时领取豆子 浏览器往下滚动的时候,倒计时开始并加载进度条,倒计时结束后领取豆子 body {min-height: 2000px}.box {position: fixed;b ...

  3. 仿淘宝京东商品规格属性选择的最简单实现

    仿淘宝京东商品规格属性选择的最简单实现 商城里面的规格选择,网上大部分是自定义控件实现的,显得很是麻烦,而我的实现方式是大家最常用的控件RecyclerView,特点是性能好,简单.废话不多说,先看实 ...

  4. 仿淘宝购物车商品颜色、尺寸选择。

    仿淘宝购买商品颜色.尺寸选择. 选项分为三种状态:可选.选中.不可选 上图看效果: 1,展示页 2,选中一个颜色,不支持的尺寸会自动变灰,成为不可点击状态 如果选择的是尺寸,同样颜色也可以自动筛选可以 ...

  5. android电子书App、自定义图表、仿腾讯漫画App、仿淘宝优惠券、3D选择容器等源码...

    Android精选源码 仿支付宝记账本功能,饼状图:数字键盘 android一款功能完善的电子书应用源码 Android自定义图标库,使用方便,扩展性强 android 3D立体无限旋转容器源码 an ...

  6. android电子书App、自定义图表、仿腾讯漫画App、仿淘宝优惠券、3D选择容器等源码... 1

    Android精选源码 仿支付宝记账本功能,饼状图:数字键盘 android一款功能完善的电子书应用源码 Android自定义图标库,使用方便,扩展性强 android 3D立体无限旋转容器源码 an ...

  7. android电子书App、自定义图表、仿腾讯漫画App、仿淘宝优惠券、3D选择容器等源码

    Android精选源码 仿支付宝记账本功能,饼状图:数字键盘 android一款功能完善的电子书应用源码 Android自定义图标库,使用方便,扩展性强 android 3D立体无限旋转容器源码 an ...

  8. iOS 仿淘宝实现商品规格图片的放大缩小功能

    刚好最近在做个商城项目,甲方爸爸说咱们要求不高,你就照着淘宝来就好,额~~~~ 好吧,咱就不吐槽了,直接开撸吧,惯例先上一下效果图 需求以及思路 我们要实现的功能有如下几个: 图片的全屏查看以及保存 ...

  9. vue仿淘宝京东商品多条件筛选(vue实现)

    <template><div id="warp">你选择的是:<mark v-for="(item,index) in arr"& ...

最新文章

  1. SDUTOJ [2801] 并查集模板
  2. jsp中include指令和动作的区别
  3. Python开发爬虫之理论篇
  4. 1/r单中心双电子积分Li+
  5. 一位7亿收入产品经理的五大绝招
  6. 工业交换机厂家有哪些?工业交换机十大品牌供应商!
  7. MMKV集成与原理,薪资翻倍
  8. Docker制作dotnet core控制台程序镜像
  9. MVVM架构~前台后台分离的思想与实践
  10. sqlserver字符串处理函数
  11. 多按键多界面二维数组表驱动设计
  12. Elgamal数字签名原理
  13. loadrunner视频资料地址-boobooke
  14. 使用PS改变背景为透明
  15. 无限级分销管理系统的设计与实现
  16. CSS3基础一篇完结(豪豪的备忘录)
  17. html5 cms结构,cms产品架构图.html
  18. 数据结构-树结构-哈夫曼应用-修理牧场
  19. bootstrapt学习指南_Bootstrap学习文档(一)
  20. 海外资产配置要注意什么?

热门文章

  1. 亲人寄语贴上公交车(图)
  2. hihocoder #1179 : 永恒游戏 暴力
  3. python 中 sys.argv函数中的用法
  4. 将USDT赶下铁王座 |链捕手
  5. Elasticsearch --基本作用以及配置
  6. 直播--FFPLAY 的原理
  7. valgrind内存检测
  8. latex tikz使用总结
  9. android 可下载字体,Android Oreo 可下载字体
  10. Jenkins slave 节点配置