当前位置: 移动技术网 > IT编程>移动开发>Android > Material Design系列之Behavior实现支付密码弹窗和商品属性选择效果

Material Design系列之Behavior实现支付密码弹窗和商品属性选择效果

2019年07月24日  | 移动技术网IT编程  | 我要评论

东风日产门户网站,答辩ppt,重庆电装有限公司

今天的效果在支付宝、淘宝、京东等电商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

效果预览

引文

在我的技术群里有小伙伴们讨论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和一个button:sheet 显示/隐藏,然后android:id="@+id/tab_layout"这个布局是横向的,给它设置了behavior:app: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对应的bottomsheetbehavior
 mbottomsheetbehavior = 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_expanded和state_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)将不会继续往上滑动,下面的内容会继续跟着出来,但是同样可以向下滑动隐藏,也可以调用dismiss和close关闭。

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() {
 @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,所以我们再次调用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() {
 @override
 public void onstatechanged(@nonnull view bottomsheet, int newstate) {
  if (newstate == bottomsheetbehavior.state_hidden) {
  mbottomsheetdialog.dismiss();
  bottomsheetbehavior.setstate(bottomsheetbehavior.state_collapsed);
  }
 }
 @override
 public void onslide(@nonnull view bottomsheet, float slideoffset) {
 }
 });
}

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

源码下载:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网