Android中的底部弹窗

组件介绍
参考资料
源码地址

介绍

底部动作条是ios中常见的界面组件,常用于呈现一组功能给用户.Android在design兼容包中也引入了这一组件和设计.用户可以自由定制动作条的视图元素和行为.
![此处输入图片的描述][1]
底部动作条的功能上看似和菜单类似,在Android中,在界面上额外弹出功能菜单有四种主要的方式:
ContextMenu -> 长按操作
OptionMenu -> 按菜单键
PopuWindow->目标控件点击
dialog ->对话框

在目前的实际开发中,前两种已经很少用到了,PopuWindow通常用来显示少量的功能(少于3个),dialog虽然能显示多个功能,但在显示时会打断用户体验,且功能个数也有限制.而且为了保持苹果,安卓的用户体验一致性.会手动设置dialog的位置为下方,以达到iOS中的底部窗口效果.

谷歌引入了底部动作条这一组件作为功能菜单展示的第五种方式,并将其作为材料设计的组成部分之后,就有必要来学习一下它的用法了.

基础布局

首先我们需要在项目中加入design兼容包的依赖,版本号与SDK中兼容包的版本号保持一致

  compile 'com.android.support:design:23.3.0'

之后是在新建项目的actiivty_main.xml 加入底部动作条

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

  <ScrollView
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingTop="24dp">

      <Button
          android:id="@+id/button_1"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:text="Button 1"
          android:padding="16dp"
          android:layout_margin="8dp"
          android:textColor="@android:color/white"
          android:background="@android:color/holo_green_dark"/>

      <Button
          android:id="@+id/button_2"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:padding="16dp"
          android:layout_margin="8dp"
          android:text="Button 2"
          android:textColor="@android:color/white"
          android:background="@android:color/holo_blue_light"/>

      <Button
          android:id="@+id/button_3"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:padding="16dp"
          android:layout_margin="8dp"
          android:text="Button 3"
          android:textColor="@android:color/white"
          android:background="@android:color/holo_red_dark"/>

    </LinearLayout>

  </ScrollView>

  <include layout="@layout/dialog_bottom_sheet"/>

</android.support.design.widget.CoordinatorLayout>

其中底部动作条的布局文件为

<android.support.v4.widget.NestedScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/bottom_sheet"
    android:layout_width="match_parent"
    android:layout_height="350dp"
    android:clipToPadding="true"
    android:background="@android:color/holo_orange_light"
    app:layout_behavior="android.support.design.widget.BottomSheetBehavior">

  <TextView
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:text="@string/ipsum"
      android:padding="16dp"
      android:textSize="16sp"/>

</android.support.v4.widget.NestedScrollView>

效果图为
![此处输入图片的描述][2]
[1]: http://aidecn.cn/MD/components-bottomsheet-for-mobile-1b_large_mdpi.png
[2]: https://cms-assets.tutsplus.com/uploads/users/798/posts/26031/image/buttons.png

注意

值得注意的是,如果要在fragmentactivity的主布局文件中显示(展示效果为不阻挡界面上其他控件的展示和点击事件),则需要布局文件的根元素为CoordinatorLayout,同时BottomSheetBehavior所标识的控件一般为可滚动的控件,如NestedScrollViewRecyclerView,具备以上两个条件之后,界面就能正常捕获和处理BottomSheet操作的事件及行为.

用下面的属性标识动作条视图的容器
app:layout_behavior="android.support.design.widget.BottomSheetBehavior"

弹出操作

在布局文件中我们可以知道,动作条视图是由BottomSheetBehavior所标识的,那么在控制动作条的显示的时候,同样也需要得到BottomSheetBehavior以控制视图的弹出状态.

MainActivity.java的代码如下

private BottomSheetBehavior mBottomSheetBehavior;

  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    View bottomSheet = findViewById( R.id.bottom_sheet );
    Button button1 = (Button) findViewById( R.id.button_1 );
    Button button2 = (Button) findViewById( R.id.button_2 );
    Button button3 = (Button) findViewById( R.id.button_3 );

    button1.setOnClickListener(this);
    button2.setOnClickListener(this);
    button3.setOnClickListener(this);

    mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
  }

接下来,要展示底部动作条的话,就需要设置BottomSheetBehavior的状态为STATE_EXPANDED,与其对应的关闭状态则为STATE_COLLAPSED,设置点击事件如下

@Override
public void onClick(View v) {
    switch( v.getId() ) {
        case R.id.button_1: {
            mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
            break;
        }
    }
}
  @Override public void onBackPressed() {

    if (mBottomSheetBehavior.getState()==BottomSheetBehavior.STATE_EXPANDED){
      mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
    }else {
      super.onBackPressed();
    }
  }

显示控制

我们可以通过设置弹出高度来控制动作条的显示高度

 mBottomSheetBehavior.setPeekHeight(300);
 mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);

同时也可以设置BottomSheetBehavior的回调函数BottomSheetCallback来动态控制动作条

mBottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
      @Override public void onStateChanged(@NonNull View bottomSheet, int newState)       {
        if (newState == BottomSheetBehavior.STATE_COLLAPSED) {
          mBottomSheetBehavior.setPeekHeight(0);
        }
      }

      @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) {

      }
});

BottomSheetDialogFragment

以上介绍的是非阻塞的底部动作条,它不会影响界面上其他元素的交互.但在iOS的底部动作视图中,是一种阻塞式的模态窗口.类似于对话框.Android中对应的就是BottomSheetDialogFragment

在其setupDialog方法中我们就可以自由定制动作条的视图及行为了,同时也需要监听动作条的状态以实现在hidden状态下的自动dismiss.

public class MyBottomSheetDialogFragment extends BottomSheetDialogFragment {
  private  BottomSheetBehavior.BottomSheetCallback callback = new BottomSheetBehavior.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) {

    }
  };


  @Override public void setupDialog(Dialog dialog, int style) {
    super.setupDialog(dialog, style);
    View contentView = View.inflate(getContext(),R.layout.dialog_bottom_sheet,null);
    dialog.setContentView(contentView);
    CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) ((View) contentView.getParent()).getLayoutParams();
    CoordinatorLayout.Behavior behavior = params.getBehavior();

    if( behavior != null && behavior instanceof BottomSheetBehavior ) {
      ((BottomSheetBehavior) behavior).setBottomSheetCallback(callback);
    }
  }
}

同DialogFragment一样,我们调用show方法来展示它

MyBottomSheetDialogFragment bottomSheetDialogFragment = new MyBottomSheetDialogFragment();
bottomSheetDialogFragment.show(getSupportFragmentManager(), bottomSheetDialogFragment.getTag());
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容