DialogFragment实现底部弹窗

作者: SpikeKing | 来源:发表于2016-06-22 22:31 被阅读9486次

    欢迎Follow我的GitHub, 关注我的简书. 其余参考Android目录.

    Bottom Dialog

    本文的合集已经编著成书,高级Android开发强化实战,欢迎各位读友的建议和指导。在京东即可购买:https://item.jd.com/12385680.html

    Android

    Android对于底部弹窗已经在23.2新的实现方式, 即BottomSheet. 然而对于低版本, 我们仍需使用DialogFragment. 底部弹窗与普通Dialog不同, 需要紧贴应用下部, 但本质仍是一个Fragment, 通过继承DialogFragment类, 定制不同样式的Fragment.

    本文源码的GitHub下载地址

    定制DialogFragment

    底部弹窗, 需要紧贴应用下部. 设置Dialog样式(Style), 全屏/布局/外部取消. 设置Dialog位置(LayoutParams), 底部/宽度最大.

    @NonNull @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // 使用不带Theme的构造器, 获得的dialog边框距离屏幕仍有几毫米的缝隙。
        Dialog dialog = new Dialog(getActivity(), R.style.BottomDialog);
    
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); // 设置Content前设定
        dialog.setContentView(R.layout.fragment_bottom);
        dialog.setCanceledOnTouchOutside(true); // 外部点击取消
    
        // 设置宽度为屏宽, 靠近屏幕底部。
        Window window = dialog.getWindow();
        WindowManager.LayoutParams lp = window.getAttributes();
        lp.gravity = Gravity.BOTTOM; // 紧贴底部
        lp.width = WindowManager.LayoutParams.MATCH_PARENT; // 宽度持平
        window.setAttributes(lp);
    
        ButterKnife.bind(this, dialog); // Dialog即View
    
        initClickTypes();
    
        return dialog;
    }
    

    ButterKnife绑定View, 但是Layout布局在Dialog初始化中设置, 所以选择绑定Dialog, 因为都继承自View.

    Dialog的样式. 宽度最大, 高度匹配, 是否浮现于Activity之上, 关闭背景暗色.

    <style name="BottomDialog" parent="@style/AppTheme">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:backgroundDimEnabled">false</item>
    </style>
    

    控制逻辑

    初始化控件组, 把图片\文字\框架组成三个控件组; 初始化框架点击事件, 点击不同的框架, 替换文字颜色与选中图片. 点击发送按钮mTvSend, 根据当前选中状态, 动态更新金币.

    private void initClickTypes() {
        initViewArray(); // 初始化控件组
        initLayout(); // 初始化框架点击事件
        
        mTvSend.setOnClickListener(new View.OnClickListener() {
            @Override public void onClick(View v) {
                String typeStr = "金币不足";
                switch (mType) {
                    case 0:
                        if (countCoins(100))
                            typeStr = "一字之师";
                        break;
                    case 1:
                        if (countCoins(200))
                            typeStr = "妙语连珠";
                        break;
                    case 2:
                        if (countCoins(800))
                            typeStr = "学识丰富";
                        break;
                    case 3:
                        if (countCoins(1200))
                            typeStr = "博学多才";
                        break;
                    default:
                        break;
                }
                Toast.makeText(getContext(), typeStr, Toast.LENGTH_SHORT).show();
            }
        });
    }
    

    初始化控件组, 框架, 文字与图片.

    private void initViewArray() {
        mLayouts = new ArrayList<>();
        mTvTypes = new ArrayList<>();
        mIvTypes = new ArrayList<>();
    
        mLayouts.add(mLlFirstContainer);
        mLayouts.add(mLlSecondContainer);
        mLayouts.add(mLlThirdContainer);
        mLayouts.add(mLlForthContainer);
    
        mTvTypes.add(mTv100Coins);
        mTvTypes.add(mTv2Yuan);
        mTvTypes.add(mTv8Yuan);
        mTvTypes.add(mTv12Yuan);
    
        mIvTypes.add(mIv100Coins);
        mIvTypes.add(mIv2Yuan);
        mIvTypes.add(mIv8Yuan);
        mIvTypes.add(mIv12Yuan);
    }
    

    Tv代表TextView的缩写, Iv代表ImageView的缩写.

    初始化布局的点击事件. 点击不同布局, 选择不同类型. mType保存当前选中的类型.

    private void initLayout() {
        chooseRegardsType(mType); // 选择默认类型
    
        for (int i = 0; i < mLayouts.size(); i++) {
            final int tmp = i;
            LinearLayout ll = mLayouts.get(i);
            ll.setOnClickListener(new View.OnClickListener() {
                @Override public void onClick(View v) {
                    mType = tmp;
                    chooseRegardsType(mType);
                }
            });
        }
    }
    

    选择类型, 根据选择类型, 设置状态, 通过状态控制

    private void chooseRegardsType(int type) {
        int size = mTvTypes.size();
        for (int i = 0; i < size; ++i) {
            if (i != type) {
                mTvTypes.get(i).setEnabled(true);
                mIvTypes.get(i).setEnabled(true);
            } else {
                mTvTypes.get(i).setEnabled(false);
                mIvTypes.get(i).setEnabled(false);
            }
        }
    }
    

    例如, Text文字的颜色, 随着状态改变.

    android:textColor="@color/regard_text_bkg"
    

    默认是灰色, 选中enable是false, 颜色是白色.

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:color="#848484" android:state_enabled="true"/>
        <item android:color="#FFFFFF" android:state_enabled="false"/>
    </selector>
    

    启动Dialog

    通过FragmentManager, 使用DialogFragment的show方法, 显示Dialog.

    public void showBottomDialog(View view) {
        FragmentManager fm = getSupportFragmentManager();
        BottomDialogFragment editNameDialog = new BottomDialogFragment();
        editNameDialog.show(fm, "fragment_bottom_dialog");
    }
    

    效果

    动画

    在DialogFragment中, 定制布局样式, 处理逻辑关系, 使用FragmentManager控制并显示Dialog, 实现经典的底部弹窗样式.

    OK, that's all! Enjoy it!

    相关文章

      网友评论

      • 9c39c18f00ce:你好 想问下 怎么设置点击出来的dialogFragment 高度随布局自适应 然后我点击其他区域响应其他的事件 现在你这个随便也是高度随布局 但是一点其他区域 作用还是在dialogFragment上 谢谢 求解答 谢谢
      • wan7451:design包
      • wan7451:v7包有,可以向下兼容
      • f04238f4b8d1:赞一个
      • 妙法莲花1234:厉害啊我的哥
      • 薄炳鑫:好东西
        SpikeKing:@薄炳鑫 对于定制的控件的实践标准.
      • 小王泽哥:想知道网易云音乐的播放列表底部弹窗用的啥。人家也是botoomsheet,难道不兼容么
        SpikeKing:@小王泽哥 他们的版本高一些.
      • SScience:个人感觉还是BottomSheet的效果酷点。你说的低版本是什么低版本呢?
        peerless2012:@SpikeKing Support高点没影响。况且BottomSheet是基于DialogFragment的,所以不会存在太大兼容心问题
        SpikeKing:@幸运Science 没有BottomSheet只能使用最早的DialogFragment做.
        SpikeKing:@幸运Science 低于23.2的版本

      本文标题:DialogFragment实现底部弹窗

      本文链接:https://www.haomeiwen.com/subject/cnendttx.html