美文网首页
Dialog自定义详解(一)

Dialog自定义详解(一)

作者: 孤独的追寻着 | 来源:发表于2017-04-03 01:40 被阅读0次

    引言

    最近公司做了一个电商的项目,运用到了非常多的Dialog自定义 ,在这里进行一下总结,以便于后面查阅资料。

    如何使用原生的Dialog

    下面就是展示原生的android代码:

    private void showNormalDialog() {
            /* @setIcon 设置对话框图标
             * @setTitle 设置对话框标题
             * @setMessage 设置对话框消息提示
             * setXXX方法返回Dialog对象,因此可以链式设置属性
             */
            final AlertDialog.Builder normalDialog =
                    new AlertDialog.Builder(DialogActivity.this);
            normalDialog.setIcon(R.mipmap.ic_launcher)
                    .setTitle("我是一个普通Dialog")
                    .setMessage("你要点击哪一个按钮呢?")
                    .setPositiveButton("确定",
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    //...To-do
                                }
                            })
                    .setNegativeButton("关闭",
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    //...To-do
                                }
                            });
            // 显示
            normalDialog.show();
        }
    

    但是大家有木有感觉原生的样式丑爆了,所以自定义弹框是每个android程序员的必修课。
    自定义弹框是非常简单的,我们该怎么写出通用,并且好用的弹框,才是我们应该学习的。

    模拟原生的Dialog写自己喜欢的Dialog

    下面我们来进入今天的实用性场景,一般开发中我们经常会出现,需要展示一些描述性的东西,提示完后你需要点选否或者是,我们来写一个关于这种简单类型的自定义Dialog:

    写DescribeDialog的布局_dialog_describe
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:id="@+id/root"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:background="@android:color/white"
                  android:orientation="vertical">
        <!-- 描述内容 -->
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
    
            <TextView
                android:id="@+id/tv_describe"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:gravity="center"
                android:maxEms="13"
                android:padding="10dp"
                android:text="这是一个描述型自定义Dialog,起到了提示的作用,
                它一行最大的字数显示在13位,maxEms起到的作用。"
                android:textSize="17sp"/>
        </RelativeLayout>
    
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#e6e6e6"/>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:orientation="horizontal">
            <!-- 取消按钮 -->
            <TextView
                android:id="@+id/tv_cancel"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center"
                android:text="取消"
                android:textColor="@android:color/holo_red_dark"
                android:textSize="17sp"/>
    
            <View
                android:layout_width="1dp"
                android:layout_height="match_parent"
                android:background="#e6e6e6"/>
            <!-- 确定按钮 -->
            <TextView
                android:id="@+id/tv_sumit"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center"
                android:text="确定"
                android:textSize="17sp"/>
        </LinearLayout>
    </LinearLayout>
    
    写DescribeDialog的类

    因为属性扩展性的自定义我们的DescribeDialog直接继承Dialog
    为了跟原生的使用方法一样,我在这里定义了Builder运用建造者模式来注入参数,我们先来看下DescribeDialogParams,也就是参数类:

      **
         * 参数类
         */
        private static class DescribeDialogParams{
            //上下文对象
            public Context mContext;
            //布局扩展器
            public LayoutInflater mInflater;
    
    
            //描述的内容
            public CharSequence describe;
            //提交按钮展示的内容
            public CharSequence sumit;
            //取消按钮展示内容
            public CharSequence cancel;
    
            //描述的字体颜色
            public int describeTextColor=-1;
            //提交按钮字体颜色
            public int sumitTextColor=-1;
            //取消按钮字体颜色
            public int cancelTextColor=-1;
    
            //是否能取消 默认是 能
            public boolean mCancelable;
    
            //确定按钮监听器
            public OnClickListener mPositiveButtonListener;
            //取消按钮监听器
            public OnClickListener mNegativeButtonListener;
    
            public DescribeDialogParams(Context context){
                mContext=context;
                mCancelable=true;
                mInflater= (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            }
    
        }
    

    注释写的很清楚了,这个类就是用来保持参数的引用,这在很多参数的时候是非常有必要的,这种方式应用于各种开源项目中,下面来看下建造者:

     /**
         * 建造者
         */
        public static class Builder {
            private  DescribeDialogParams P;
            private int mTheme;
    
    
            public Builder(@NonNull Context context) {
                this(context,R.style.NoTitleDialog);
            }
            public Builder(@NonNull Context context,int themeResId) {
                P=new DescribeDialogParams(context);
                this.mTheme=themeResId;
            }
    
            public Context getContext() {
                return P.mContext;
            }
    
            /**
             *
             * @param describe 设置描述的内容
             * @return
             */
            public Builder setDescribe(CharSequence describe){
                P.describe=describe;
                return this;
            }
    
            /**
             *
             * @param sumit 设置提交按钮的展示内容
             * @param onClickListener 提交按钮的监听器
             * @return
             */
            public Builder setPositiveButton(CharSequence sumit,OnClickListener onClickListener){
                P.sumit=sumit;
                P.mPositiveButtonListener=onClickListener;
                return this;
            }
    
            /**
             *
             * @param cancel 设置取消按钮的展示内容
             * @param onClickListener 取消按钮的监听器
             * @return
             */
            public Builder setNegativeButton(CharSequence cancel,OnClickListener onClickListener){
                P.cancel=cancel;
                P.mNegativeButtonListener=onClickListener;
                return this;
            }
            /**
             *
             * @param describeTextColor 设置描述内容的字体颜色
             * @return
             */
            public Builder setDescribeTextColor(int describeTextColor){
                P.describeTextColor=describeTextColor;
                return this;
            }
    
            /**
             *
             * @param sumitTextColor 设置提交按钮的字体颜色
             * @return
             */
            public Builder setSumitTextColor(int sumitTextColor){
                P.sumitTextColor=sumitTextColor;
                return this;
            }
    
            /**
             *
             * @param cancelTextColor 设置取消按钮的字体颜色
             * @return
             */
            public Builder setCancelTextColor(int cancelTextColor){
                P.cancelTextColor=cancelTextColor;
                return this;
            }
    
            /**
             * 创建DescribeDialog
             * @return DescribeDialog
             */
            public DescribeDialog create() {
                final DescribeDialog dialog = new DescribeDialog(P.mContext,mTheme);
                dialog.setP(P);
                return dialog;
            }
    
            /**
             *展示DescribeDialog
             * @return DescribeDialog
             */
            public DescribeDialog show() {
                final DescribeDialog dialog = create();
                dialog.show();
                return dialog;
            }
        }
    

    建造者也比较简单,就是参数的注入,然后返回当前建造的对象,这种对于参数多的情况下链式结构注入参数,还有就是有必要提醒的是,show()方法必须在create()之后执行,之前注入的参数才有效。
    我们再来看看DescribeDialog类:

       private Context mContext;
        private TextView tvDescribe;
        private TextView tvCancel;
        private TextView tvSumit;
        private DescribeDialog(Context context, int themeResId) {
            super(context, themeResId);
            this.mContext=context;
        }
    
        private void setP(DescribeDialogParams p) {
            P = p;
        }
    
        private  DescribeDialogParams P;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            init();
        }
    
        private void init() {
            View view = P.mInflater.inflate(R.layout.dialog_describe, null);
            setContentView(view);
            Window dialogWindow = getWindow();
            WindowManager.LayoutParams lp = dialogWindow.getAttributes();
            DisplayMetrics d = mContext.getResources().getDisplayMetrics(); // 获取屏幕宽、高用
            lp.width = (int) (d.widthPixels * 0.8); // 高度设置为屏幕的0.6
            dialogWindow.setAttributes(lp);
            //点击外部不关闭
            setCancelable(P.mCancelable);
    
            //初始化View
            tvDescribe= (TextView) view.findViewById(R.id.tv_describe);
            tvCancel= (TextView) view.findViewById(R.id.tv_cancel);
            tvSumit= (TextView) view.findViewById(R.id.tv_sumit);
            //设置颜色
            if (P.describeTextColor!=-1){
                tvDescribe.setTextColor(P.describeTextColor);
            }
            if (P.cancelTextColor!=-1){
                tvCancel.setTextColor(P.cancelTextColor);
            }
            if (P.sumitTextColor!=-1){
                tvSumit.setTextColor(P.sumitTextColor);
            }
            //设置内容显示
            if (!TextUtils.isEmpty(P.describe)){
                tvDescribe.setText(P.describe);
            }
            if (!TextUtils.isEmpty(P.cancel)){
                tvCancel.setText(P.cancel);
            }
            if (!TextUtils.isEmpty(P.sumit)){
                tvSumit.setText(P.sumit);
            }
            //监听器
            tvSumit.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    dismiss();
                    if (P.mPositiveButtonListener!=null){
                        P.mPositiveButtonListener.onClick(tvSumit.getId());
                    }
                }
            });
            tvCancel.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    dismiss();
                    if (P.mNegativeButtonListener!=null){
                        P.mNegativeButtonListener.onClick(tvSumit.getId());
                    }
                }
            });
        }
    
    

    大家看代码,可以看到,DescribeDialog类有DescribeDialogParams的依赖,当我们需要参数的值的时候直接从DescribeDialogParams中取,这种建造者模式就是我们自定义Dialog的精髓所在,然后最重要的方法就在init()方法中,对View的扩展,使用布局扩展器扩展出View后通过setContentView(view)来设置到Dialog中,有木有感觉Dialog就是一个Activity,之后就是一些对Dialog宽高的设置。

    相关文章

      网友评论

          本文标题:Dialog自定义详解(一)

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