Android底部对话框的实现(BottomSheet,自定义Dialog)

前言

在底部弹出一个对话框,在应用中很常见,现在说一下几种实现的方案,记录一下,算是一个总结吧!

实现方案

使用BottomSheetDialog

BottomSheetDialog是support design包下的一个控件,它算是BottomSheet衍生出来的一个特例吧,类似的还有BottomSheetDialogFragment,这些控件的一个核心就是BottomSheetBehavior<V>,它继承CoordinatorLayout.Behavior<V>,说到CoordinatorLayout.Behavior<V>,就不得不提到CoordinatorLayout,可能我们对另一个behavoir比较熟悉,就是AppbarLayoutBehavior,来协调CoordinatorLayout内其他控件和AppbarLayout内控件的相对位置。同样的,BottomSheetBehavior<V>也是如此。好吧,跑题了,这些内容有兴趣的可以查阅资料了解一下。

Bottom Sheet

下边先简单说一下Bottom Sheet的使用:
首先在我们的布局中添加:

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/coorlayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.xxx.mybottomsheetdemo.MainActivity">

    <LinearLayout
        android:id="@+id/bottom_sheet_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="16dp"
        app:behavior_peekHeight="0dp"
        app:behavior_hideable="true"
        app:layout_behavior="@string/bottom_sheet_behavior">
        <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="微信"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="QQ"/>

    </LinearLayout>


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

需要注意的地方:
1. 父布局必须是CoordinatorLayout。
2. 需要在弹出的布局中添加属性:
app:layout_behavior="@string/bottom_sheet_behavior"
3. 另外app:behavior_peekHeight="0dp"表示当Bottom Sheets关闭的时候,底部下表我们能看到的高度;app:behavior_hideable="true"表示当我们拖拽下拉的时候,bottom sheet是否能全部隐藏。当然这些属性我们在代码中也可以设置。

然后,在代码中这样使用:

View bottom_view = (LinearLayout) findViewById(R.id.bottom_sheet_view);
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottom_view);
//behavior.setPeekHeight();//sheet关闭时,下边可见的高度
behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
    @Override
    public void onStateChanged(@NonNull View bottomSheet, int newState) {
        //这里是bottomSheet 状态的改变
        switch (newState) {
            case BottomSheetBehavior.STATE_EXPANDED:

                break;
            case BottomSheetBehavior.STATE_COLLAPSED:

                break;
            default:
                break;
            }
    }

    @Override
    public void onSlide(@NonNull View bottomSheet, float slideOffset) {
        //这里是拖拽中的回调
        }
});

如果你需要监听Bottom Sheets回调的状态,可以通过setBottomSheetCallback来实现,onSlide方法是拖拽中的回调,根据slideOffset可以做一些动画。onStateChanged方法可以监听到状态的改变,总共有5种

  • STATE_COLLAPSED: 关闭Bottom Sheets,显示peekHeight的高度,默认是0
  • STATE_DRAGGING: 用户拖拽Bottom Sheets时的状态
  • STATE_SETTLING: 当Bottom Sheets view释放时记录的状态。
  • STATE_EXPANDED: 当Bottom Sheets 展开的状态
  • STATE_HIDDEN: 当Bottom Sheets 隐藏的状态

另外这里边还有一点需要注意:
如果Bottom Sheet中有需要滑动的视图,必须支持嵌套滑动才行。比如:NestedScrollView、RecyclerView或者API 21 + 上的ListView、ScrollView。否则,滑动只是关闭掉Bottom Sheet而已!

BottomSheetDialog

BottomSheetDialog,跟一般的Dialog一样,是一个从底部弹出的对话框,使用的API都和一般的Dialog一样。

这里有一点,就是在弹出对话框的时候,状态栏会变黑,如果不想这样,可以看一下我之前的一篇博客:解决使用BottomSheetDialog时状态栏变黑的问题
如果没有必要,则直接使用即可!

MyBottomSheetDialog dialog = new MyBottomSheetDialog(this);
View view = getLayoutInflater().inflate(R.layout.bottom_sheet_dialog, null);
dialog.setContentView(view);
dialog.show();

自定义Dialog

①首先我们自定义一个Dialog的style

<!-- 底部对话框样式 -->
    <style name="dialog_bottom_full" parent="android:style/Theme.Dialog">
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:scrollHorizontally">true</item>
    </style>

当然,我们可以根据需要,添加或者删除一些属性。
②在代码中使用:

View view = LayoutInflater.from(getActivity()).inflate(R.layout.bottom_choose_section, null);
Dialog dialog = new Dialog(this, R.style.dialog_bottom_full);
Window window = dialog.getWindow();
window.setGravity(Gravity.BOTTOM);
window.setContentView(view);

WindowManager.LayoutParams lp = window.getAttributes(); // 获取对话框当前的参数值
lp.width = WindowManager.LayoutParams.MATCH_PARENT;//宽度占满屏幕
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setAttributes(lp);        
dialog.show();

需要注意的地方:
①我们在初始化Dialog的时候,必须加上自己的Style。
window.setGravity(Gravity.BOTTOM);设置在底部
③如果我们不是使用的window.setContentView(view);而是dialog.setContentView(view),那么我们需要在后边添加window.getDecorView().setPadding(0, 0, 0, 0);,去掉Dialog默认自带的padding。

④在设置宽高的时候,如果嫌设置WindowManager步骤麻烦,那么直接

window.setLayout(WindowManager.LayoutParams.MATCH_PARENT,WindowManager.LayoutParams.WRAP_CONTENT);

是一样的。

⑤如果我们想对对话框弹出或者退出时添加动画,则:

window.setWindowAnimations(R.style.dialogstyle); // 添加动画  

R.style.dialogstyle

<style name="dialogstyle" parent="android:Animation">  
    <item name="@android:windowEnterAnimation">@anim/dialog_enter</item>  //进入时的动画  
    <item name="@android:windowExitAnimation">@anim/dialog_exit</item>    //退出时的动画  
</style>  

res/anim/dialog_enter.xml

<?xml version="1.0" encoding="utf-8"?>  
<set xmlns:android="http://schemas.android.com/apk/res/android">   
    <translate  
        android:fromYDelta="100%p"   <!--%p指相对于父容器-->  
        android:duration="400"/>  <!--持续时间-->
</set> 

使用PopupWindow

直接上代码:

View view = getLayoutInflater().inflate(R.layout.layout_popup, null);
View rootview = getLayoutInflater().inflate(R.layout.activity_main, null);
PopupWindow popupWindow = new PopupWindow(MainActivity.this);
popupWindow.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
popupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
popupWindow.setContentView(view);
popupWindow.setBackgroundDrawable(new ColorDrawable(0x00000000));
popupWindow.setFocusable(true);
popupWindow.setOutsideTouchable(true);
popupWindow.showAtLocation(rootview, Gravity.BOTTOM, 0, 0);

关键就是这一句:popupWindow.showAtLocation(rootview, Gravity.BOTTOM, 0, 0);设置在底部,当然我们也可以给其加一下动画。
关于PopupWindow的用法,这里就不再赘述了!
可以参考一下这篇文章:浅谈PopupWindow在Android开发中的使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值