通过构造者模式做一个通用的自定义dialog弹窗

点点圈 提交于 2019-12-11 17:53:39

app开发肯定少不了各种样式的弹窗,这里分享一个自己一直在用的自定义dialog弹窗,简化了创建dialog里重复操作。

先上代码

public class CustomDialog extends Dialog {

    private MyDialogListener listener;//外部设置的监听回调
    private int dialogId = -1;//通过dialogId 区分同一页面多个弹窗
    private DialogOnClickListener onClickListener = new DialogOnClickListener();//implements实现View.OnClickListener
    private ViewGroup contentView;//dialog的布局对象

    public CustomDialog(Context context) {
        super(context);
    }

    public CustomDialog(@NonNull Context context, @StyleRes int themeResId) {
        super(context, themeResId);
    }

    public void setTextViewText(int id, String text) {
        TextView tv = contentView.findViewById(id);
        if (tv != null)
            tv.setText(text);
    }

    public void setTextViewSize(int id, int size) {
        TextView tv = contentView.findViewById(id);
        if (tv != null)
            tv.setTextSize(size);
    }

    public void setTextViewText(int id, SpannableString text) {
        TextView tv = contentView.findViewById(id);
        if (tv != null)
            tv.setText(text);
    }

    public void setTvLineSpacing(int id, int dp) {
        TextView tv = contentView.findViewById(id);
        if (tv != null)
            tv.setLineSpacing(dp, 1);
    }

    public void setImageView(int id, int resId) {
        ImageView iv = contentView.findViewById(id);
        iv.setImageResource(resId);
    }

    public void setTextColor(int id, int color) {
        TextView tv = contentView.findViewById(id);
        if (tv != null)
            tv.setTextColor(color);
    }

    public void setViewVisible(int id, int visible) {
        contentView.findViewById(id).setVisibility(visible);
    }

    public void setViewVisible(int id, boolean visible) {
        contentView.findViewById(id).setVisibility(visible ? View.VISIBLE : View.GONE);
    }

    public void setDialogId(int dialogId) {
        this.dialogId = dialogId;
    }

    private void setRootView(ViewGroup viewGroup) {
        this.contentView = viewGroup;
        setContentView(viewGroup);
    }


    /**
     * 遍历根布局  给每个有id的控件添加点击监听
     *
     * @param view
     */
    private void traverseParent(View view) {
        if (view instanceof ViewGroup) {
            if (view instanceof ViewPager) {
                if (view.getId() != -1) {
                    addViewClick(view);
                }
            } else {
                for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
                    if (((ViewGroup) view).getChildAt(i).getId() != -1) {
                        addViewClick(((ViewGroup) view).getChildAt(i));
                    }
                    if (((ViewGroup) view).getChildAt(i) instanceof ViewGroup) {
                        traverseParent(((ViewGroup) view).getChildAt(i));
                    }
                }
            }
        } else {
            if (view.getId() != -1) {
                addViewClick(view);
            }
        }
    }

    public View findViewById(int id) {
        return contentView.findViewById(id);
    }

    private void addViewClick(View view) {
        view.setOnClickListener(onClickListener);
    }

    public int getDialogId() {
        return dialogId;
    }

    /**
     * dialog的按钮监听回调
     */
    public interface MyDialogListener {
        void onClick(View view, int dialogId, CustomDialog dialog);
    }

    public void setDialogListener(MyDialogListener listener) {
        this.listener = listener;
    }

    private class DialogOnClickListener implements View.OnClickListener {

        @Override
        public void onClick(View v) {
            if (listener != null) {
                listener.onClick(v, dialogId, CustomDialog.this);
            }
        }
    }

    /**
     * 构造dialog的参数类
     */
    private static class MyDialogParams {
        public boolean canceledOnTouchOutside = true, cancelable = true;
        public int width = ViewGroup.LayoutParams.MATCH_PARENT, height = ViewGroup.LayoutParams.WRAP_CONTENT,
                gravity = Gravity.CENTER, dialogId = -1, styleId = -1, layoutId = -1;
        public MyDialogListener listener = null;
        private ViewGroup view;
        private Context context;

        public MyDialogParams(Context context) {
            this.context = context;
        }

        public void initDialog(CustomDialog dialog) {
            dialog.setCanceledOnTouchOutside(canceledOnTouchOutside);
            dialog.setCancelable(cancelable);
            dialog.getWindow().setGravity(gravity);

            if (gravity == Gravity.BOTTOM)
                dialog.getWindow().setWindowAnimations(R.style.bottomDialog_Animation);

            view = (ViewGroup) LayoutInflater.from(context).inflate(layoutId, null);
            dialog.setRootView(view);
            view.getLayoutParams().width = width;
            view.getLayoutParams().height = height;
            if (listener != null)
                dialog.setDialogListener(listener);

            if (dialogId != -1)
                dialog.setDialogId(dialogId);
            dialog.traverseParent(view);
        }
    }

    public static class Builder {

        private MyDialogParams p;
        private Context context;

        public Builder(Context context) {
            this.context = context;
            p = new MyDialogParams(context);
        }

        public Builder setContentView(int layoutId) {
            p.layoutId = layoutId;
            return this;
        }

        public Builder setCancelable(boolean cancelable) {
            p.cancelable = cancelable;
            return this;
        }

        public Builder setCanceledOnTouchOutside(boolean canceledOnTouchOutside) {
            p.canceledOnTouchOutside = canceledOnTouchOutside;
            return this;
        }

        public Builder setDialogListener(MyDialogListener listener) {
            p.listener = listener;
            return this;
        }

        public Builder setDialogWidth(int width) {
            p.width = width;
            return this;
        }

        public Builder setDialogHeight(int height) {
            p.height = height;
            return this;
        }

        public Builder setDialogGravity(int gravity) {
            p.gravity = gravity;
            return this;
        }

        public Builder setDialogId(int dialogId) {
            p.dialogId = dialogId;
            return this;
        }

        public Builder setStyleId(int styleId) {
            p.styleId = styleId;
            return this;
        }

        public CustomDialog create() {
            if (p.layoutId == -1) {
                try {
                    throw new Exception("请先设置layoutId");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            CustomDialog dialog;
            if (p.styleId == -1)
                dialog = new CustomDialog(this.context, R.style.normalDialog);
            else
                dialog = new CustomDialog(this.context, p.styleId);

            p.initDialog(dialog);
            return dialog;
        }

    }

}

 

 

 

 

这里举最常见的两种例子

第一种是标准的确认弹窗(含一个标题文本,一个内容文本,取消按钮和确定按钮)

 

代码如下

java代码

private void showStandardDialog() {
        CustomDialog dialog = new CustomDialog.Builder(context)
                .setContentView(R.layout.dialog_standard)
                .setDialogId(DIALOG_STANDARD)
                .setDialogWidth(DeviceUtils.getDialogWidth(context, 80))
                .setDialogGravity(Gravity.CENTER)
                .setDialogListener(new CustomDialog.MyDialogListener() {
                    @Override
                    public void onClick(View view, int dialogId, CustomDialog dialog) {
                        //此处 dialogId 为 DIALOG_STANDARD
                        switch (view.getId()) {
                            case R.id.tv_left:
                                dialog.dismiss();
                                break;
                            case R.id.tv_right:
                                Toast.makeText(context, "点击确定", Toast.LENGTH_SHORT).show();
                                dialog.dismiss();
                                break;
                        }
                    }
                }).create();
        dialog.setTextViewText(R.id.tv_title, "这个是标题");
        dialog.setTextViewText(R.id.tv_content, "这个是内容内容内容内容内容内容内容内容内容内容内容内容内容内容");
        dialog.show();
    }

xml文件

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content"
    android:background="@drawable/bg_white_radius_5_boder_0"
    android:paddingTop="20dp">

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="25dp"
        android:layout_marginRight="25dp"
        android:gravity="center"
        android:text="title"
        android:textColor="#333"
        android:textSize="18sp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv_content"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="25dp"
        android:layout_marginTop="5dp"
        android:layout_marginRight="25dp"
        android:gravity="center"
        android:text="content"
        android:textColor="#666"
        android:textSize="16sp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tv_title" />

    <View
        android:id="@+id/line1"
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginTop="20dp"
        android:background="#f2f2f2"
        app:layout_constraintTop_toBottomOf="@id/tv_content" />

    <TextView
        android:id="@+id/tv_left"
        android:layout_width="0dp"
        android:layout_height="46dp"
        android:gravity="center"
        android:text="取消"
        android:textColor="#ff0000"
        android:textSize="16sp"
        android:visibility="visible"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/tv_right"
        app:layout_constraintTop_toBottomOf="@id/line1" />

    <TextView
        android:id="@+id/tv_right"
        android:layout_width="0dp"
        android:layout_height="46dp"
        android:gravity="center"
        android:text="确定"
        android:textColor="#0069FF"
        android:textSize="16sp"
        app:layout_constraintLeft_toRightOf="@id/tv_left"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/line1" />

    <View
        android:id="@+id/line2"
        android:layout_width="1dp"
        android:layout_height="23dp"
        android:background="#f2f2f2"
        app:layout_constraintLeft_toRightOf="@id/tv_left"
        app:layout_constraintRight_toLeftOf="@id/tv_right"
        app:layout_constraintBottom_toBottomOf="@id/tv_left"
        app:layout_constraintTop_toTopOf="@id/tv_left" />

</androidx.constraintlayout.widget.ConstraintLayout>

可以通过dialog.setViewVisible(控件id,int visible)方法控制显示的文本或者按钮数量来复用dialog_standard.xml布局显示不同样式

比如:


将前面弹窗方法中的
dialog.setTextViewText(R.id.tv_title, "这个是标题");
dialog.setTextViewText(R.id.tv_content, "这个是内容内容内容内容内容内容内容内容内容内容内容内容内容内容");
这两段修改为下面几段

dialog.setTextViewText(R.id.tv_title, "这个是标题标题标题标题标题标题标题标题标题标题标题标题");
dialog.setViewVisible(R.id.tv_content,false);
dialog.setViewVisible(R.id.tv_right,false);
dialog.setViewVisible(R.id.line2,false);
dialog.setTextViewText(R.id.tv_left,"知道了");
dialog.setTextColor(R.id.tv_left, Color.parseColor("#0069FF"));
就能变为单一内容+单一按钮的通知确认弹窗

第二种例子

常见的底部弹窗

代码如下:

private void showBottomDialog() {
        CustomDialog dialog = new CustomDialog.Builder(context)
                .setContentView(R.layout.dialog_bottom_menu)
                .setDialogId(DIALOG_BOTTOM)//自己定义的int数值
                .setCancelable(false)//是否能点击取消关闭  默认为true
                .setCanceledOnTouchOutside(false)//是否能点击空白区域关闭弹窗  默认为true
                .setDialogWidth(DeviceUtils.getWindowWidth(context))
                .setDialogGravity(Gravity.BOTTOM)
                .setDialogListener(new CustomDialog.MyDialogListener() {
                    @Override
                    public void onClick(View view, int dialogId, CustomDialog dialog) {
                        //此处 dialogId 为 DIALOG_STANDARD
                        switch (view.getId()) {
                            case R.id.tv_cancel:
                                dialog.dismiss();
                                break;
                            case R.id.tv_first:
                                Toast.makeText(context, "点击第一个按钮", Toast.LENGTH_SHORT).show();
                                dialog.dismiss();
                                break;
                            case R.id.tv_second:
                                Toast.makeText(context, "点击第二个按钮", Toast.LENGTH_SHORT).show();
                                dialog.dismiss();
                                break;
                        }
                    }
                }).create();
        dialog.setTextViewText(R.id.tv_first, "第一个按钮");
        dialog.setTextViewText(R.id.tv_second, "第二个按钮");
        dialog.setTextViewText(R.id.tv_cancel, "这是个取消按钮");

        //两句相同效果  隐藏id为tv_third的按钮
        dialog.setViewVisible(R.id.tv_third, View.GONE);
        dialog.setViewVisible(R.id.tv_third, false);

        dialog.show();
    }

xml文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#f2f2f2"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_first"
        android:layout_width="match_parent"
        android:layout_height="46dp"
        android:layout_marginTop="1dp"
        android:background="#fff"
        android:gravity="center"
        android:text="first"
        android:textColor="#333"
        android:textSize="16sp" />

    <TextView
        android:id="@+id/tv_second"
        android:layout_width="match_parent"
        android:layout_height="46dp"
        android:layout_marginTop="1dp"
        android:background="#fff"
        android:gravity="center"
        android:text="second"
        android:textColor="#333"
        android:textSize="16sp" />

    <TextView
        android:id="@+id/tv_third"
        android:layout_width="match_parent"
        android:layout_height="46dp"
        android:layout_marginTop="1dp"
        android:background="#fff"
        android:gravity="center"
        android:text="third"
        android:textColor="#333"
        android:textSize="16sp" />

    <TextView
        android:id="@+id/tv_cancel"
        android:layout_width="match_parent"
        android:layout_height="46dp"
        android:layout_marginTop="10dp"
        android:background="#fff"
        android:gravity="center"
        android:text="cancel"
        android:textColor="#333"
        android:textSize="16sp" />

</LinearLayout>

这个自定义dialog 只需要写好xml,然后设置文本或者一些控件显隐的状态变化就能适应大多数情况,特殊情况也可以通过dialog.findViewById单拉出来使用。 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!