Android 使用Builder设计模式打造通用的Dialog

2017-12-27  本文已影响237人  Sky_Blue
一、Builder设计模式的定义
将一个复杂对象的构建和它的表现分离,使得同样的构建过程,可以创建不同的表示。
二、Android使用系统的Dialog
//1.得到对话框的构造器,可以构造对话的模版
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("标题");
builder.setMessage("包含内容");
//2.添加一个确定按钮
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {

    }
});
//3.添加一个取消按钮
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {

    }
});
//4.使用构造器创建一个对话框的对象
AlertDialog dialog = builder.create();
//5.显示对话框
dialog.show();
三、安际开发情况
由于每个APP的风格不一样,UI设计的弹窗五花八门,系统的Dialog用得不多。系统的Dialog定制性不强等等。
由于系统的Dialog有诸多的不便,自己写一个通用的可定制的Dialog就是必要的了。
四、Dialog都有哪些通用特性?
1.Dialog的显示动画、位置,常用的是由下面出来和中间出来。
2.Dialog的背景,包括背景色、背景圆角。
3.其它的一些设置,用Dialog系统有的就行了,比如取消监听等等
五、Dialog的Builder控制建造类,主要是设置Dialog构建的一些参数。
/**
 * Dialog的Builder控制建造类
 */
public class QuickBuilder {
    private QuickDialog mDialog;
    public boolean mCancelable = true;
    public DialogInterface.OnCancelListener mOnCancelListener;
    public DialogInterface.OnDismissListener mOnDismissListener;
    public DialogInterface.OnKeyListener mOnKeyListener;
    /**
     * Dialog的View 与Dialog的布局ID 设置一个即可
     */
    public View mView;
    /**
     * Dialog的View 与Dialog的布局ID 设置一个即可
     */
    public int mViewLayoutResId;
    /**
     * 存放文本的集合
     */
    public SparseArray<CharSequence> mTextArray = new SparseArray<>();
    /**
     * 存放点击事件的集合
     */
    public SparseArray<View.OnClickListener> mClickArray = new SparseArray<>();
    /**
     * 宽,默认是屏幕的宽
     */
    public int mWidth;
    public int mHeight = ViewGroup.LayoutParams.WRAP_CONTENT;
    /**
     * 显示位置
     */
    public int mGravity = Gravity.CENTER;
    /**
     * 显示动画
     */
    public int mAnimation;
    /**
     * 宽,默认缩放
     */
    public float mScale = 0.85f;
    /**
     * 背景圆角,默认5
     */
    public int mBgRadius = 5;
    /**
     * 背景色,默认白色
     */
    public int mBgColor = Color.parseColor("#ffffffff");
    /**
     * 是否模糊
     */
    public boolean isDimEnabled = true;


    private QuickBuilder(Context context, int themeResId) {
        DisplayMetrics dm = context.getResources().getDisplayMetrics();
        mWidth = dm.widthPixels;
        this.mDialog = new QuickDialog(context, themeResId);
    }

    private QuickBuilder(Context context) {
        // 默认主题,在style配置,下面给出
        this(context, R.style.Theme_Dialog);
    }

    public static QuickBuilder create(Context context, int themeResId) {
        return new QuickBuilder(context, themeResId);
    }

    public static QuickBuilder create(Context context) {
        return new QuickBuilder(context);
    }

    public QuickBuilder setText(int viewId, CharSequence text) {
        mTextArray.put(viewId, text);
        return this;
    }

    public QuickBuilder setOnClickListener(int viewId, View.OnClickListener onClickListener) {
        mClickArray.put(viewId, onClickListener);
        return this;
    }

    /**
     * 设置显示的View
     */
    public QuickBuilder setContentView(int layoutResId) {
        mView = null;
        mViewLayoutResId = layoutResId;
        return this;
    }

    /**
     * 设置显示的布局
     */
    public QuickBuilder setContentView(View view) {
        mView = view;
        mViewLayoutResId = 0;
        return this;
    }

    /**
     * 设置ContentView背景的颜色:默认白色
     */
    public QuickBuilder setContentViewBgColor(int resId) {
        mBgColor = resId;
        return this;
    }

    /**
     * 设置ContentView背景的圆角:默认10dp
     *
     * @param radus 内部已转成dp
     * @return
     */
    public QuickBuilder setContentViewBgRadius(int radus) {
        mBgRadius = radus;
        return this;
    }

    /**
     * 设置背景是否模糊:默认是模糊的
     *
     * @param isDimEnabled
     * @return
     */
    public QuickBuilder setIsDimEnabled(boolean isDimEnabled) {
        this.isDimEnabled = isDimEnabled;
        return this;
    }

    /**
     * 设置宽度占满的比例
     */
    public QuickBuilder setWidthScale(float scale) {
        mScale = scale;
        return this;
    }

    public QuickBuilder fullWidth() {
        mScale = 1.0f;
        return this;
    }

    public QuickBuilder fromBottom(boolean isAnim) {
        if (isAnim) {
            mAnimation = R.style.Anim_Dialog_Bottom;
        }
        mGravity = Gravity.BOTTOM;
        return this;
    }

    public QuickBuilder setAnimation(int resId) {
        mAnimation = resId;
        return this;
    }


    public QuickBuilder setWidth(int width) {
        mWidth = width;
        return this;
    }

    public QuickBuilder setHeight(int height) {
        mHeight = height;
        return this;
    }

    /**
     * 设置点击空白是否消失
     */
    public QuickBuilder setCancelable(boolean cancelable) {
        mCancelable = cancelable;
        return this;
    }

    /**
     * 设置取消的监听
     */
    public QuickBuilder setOnCancelListener(DialogInterface.OnCancelListener onCancelListener) {
        mOnCancelListener = onCancelListener;
        return this;
    }

    /**
     * 设置Dialog消息的监听
     */
    public QuickBuilder setOnDismissListener(DialogInterface.OnDismissListener onDismissListener) {
        mOnDismissListener = onDismissListener;
        return this;
    }

    /**
     * 设置按键的监听
     */
    public QuickBuilder setOnKeyListener(DialogInterface.OnKeyListener onKeyListener) {
        mOnKeyListener = onKeyListener;
        return this;
    }

    public QuickDialog create() {
        mDialog.apply(this);
        return mDialog;
    }

    public QuickDialog show() {
        QuickDialog dialog = create();
        dialog.show();
        return dialog;
    }
}
六、Dialog View显示的辅助类,主要是加载View布局和找到里面的View等
/**
 * Dialog View显示的辅助类
 */
public class ViewHelper {
    /**
     * Dialog显示的View
     */
    private View mContentView;
    private SparseArray<WeakReference<View>> mViews = new SparseArray<>();

    public ViewHelper(Context context, int layoutResId) {
        mContentView = LayoutInflater.from(context).inflate(layoutResId, null);
    }

    public ViewHelper(View mView) {
        mContentView = mView;
    }
    public View getContentView() {
        return mContentView;
    }
    /**
     * 设置文本
     */
    public void setText(int viewId, CharSequence charSequence) {
        TextView tv = getView(viewId);
        if (tv != null && charSequence != null) {
            tv.setText(charSequence);
        }
    }
    public <T extends View> T getView(int viewId) {
        WeakReference<View> viewWeakReference = mViews.get(viewId);
        View view = null;
        if (viewWeakReference == null) {
            view = mContentView.findViewById(viewId);
            if (view != null) {
                mViews.put(viewId, new WeakReference<>(view));
            }
        } else {
            view = viewWeakReference.get();
        }
        return (T) view;
    }
    /**
     * 设置点击事件
     */
    public void setOnClickListener(int viewId, View.OnClickListener onClickListener) {
        View view = getView(viewId);
        if (view != null && onClickListener != null) {
            view.setOnClickListener(onClickListener);
        }
    }
}
六、自定义通用的Dialog
/**
 * 自定义通用的Dialog
 */
public class QuickDialog extends Dialog {
    private ViewHelper mViewHelper = null;
    public QuickDialog(@NonNull Context context, @StyleRes int themeResId) {
        super(context, themeResId);
    }

    /**
     * 绑定和设置参数
     */
    public QuickDialog apply(QuickBuilder params) {
        // 1.设置布局
        mViewHelper = null;
        if (params.mViewLayoutResId != 0) {
            mViewHelper = new ViewHelper(getContext(), params.mViewLayoutResId);
        }
        if (params.mView != null) {
            mViewHelper = new ViewHelper(params.mView);
        }
        if (mViewHelper == null) {
            throw new IllegalArgumentException("请调用setContentView方法设置布局");
        }
        // 创建前景和圆角
        final GradientDrawable bg = new GradientDrawable();
        float radius = dp2px(params.mBgRadius);
        bg.setCornerRadii(new float[]{radius, radius, radius, radius, radius, radius, radius, radius});// 1 2 3 4(顺时针)
        bg.setColor(params.mBgColor);
        // 设置背景
        View contentView = mViewHelper.getContentView();
        // 设置Dialog的布局
        setContentView(contentView);
        // 设置背景
        contentView.setBackgroundDrawable(bg);
        // 是否可以取消
        setCancelable(params.mCancelable);
        // 设置监听
        if (params.mOnCancelListener != null) {
            setOnCancelListener(params.mOnCancelListener);
        }
        if (params.mOnDismissListener != null) {
            setOnDismissListener(params.mOnDismissListener);
        }
        if (params.mOnKeyListener != null) {
            setOnKeyListener(params.mOnKeyListener);
        }

        Window window = getWindow();
        // 显示的位置
        window.setGravity(params.mGravity);
        // 动画
        if (params.mAnimation != 0) {
            window.setWindowAnimations(params.mAnimation);
        }
        // 宽高
        WindowManager.LayoutParams windowAttributes = window.getAttributes();
        windowAttributes.width = (int) (params.mWidth * params.mScale);
        windowAttributes.height = params.mHeight;
        window.setAttributes(windowAttributes);
        // 设置背景是否模糊
        if (!params.isDimEnabled) {
            window.setDimAmount(0f);
        }
        // 设置文本
        int textSize = params.mTextArray.size();
        for (int i = 0; i < textSize; i++) {
            mViewHelper.setText(params.mTextArray.keyAt(i), params.mTextArray.valueAt(i));
        }
        // 设置点击
        int clickSize = params.mClickArray.size();
        for (int i = 0; i < clickSize; i++) {
            mViewHelper.setOnClickListener(params.mClickArray.keyAt(i), params.mClickArray.valueAt(i));
        }
        return this;
    }

    public int dp2px(float dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getContext().getResources().getDisplayMetrics());
    }

    public void setText(int viewId, CharSequence text) {
        mViewHelper.setText(viewId, text);
    }

    public void setOnClickListener(int viewId, View.OnClickListener onClickListener) {
        mViewHelper.setOnClickListener(viewId, onClickListener);
    }

    public <T extends View> T getView(int viewId) {
        return mViewHelper.getView(viewId);
    }
}
七、Dialog默认显示的主题
 <!--从下弹出来的基本动画-->
    <style name="Anim_Dialog_Bottom" parent="@style/Theme.AppCompat.Dialog">
        <item name="android:windowEnterAnimation">@anim/slide_in</item>
        <item name="android:windowExitAnimation">@anim/slide_out</item>
    </style>

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!--slide_in-->
    <translate
        android:duration="250"
        android:fromXDelta="0"
        android:fromYDelta="100%"
        android:toXDelta="0"
        android:toYDelta="0" />
</set>

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!--slide_out-->
    <translate
        android:duration="250"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="0"
        android:toYDelta="100%" />
</set>
八、Dialog的使用
QuickDialog dialog = QuickBuilder.create(this)
        .setContentView(R.layout.dialog_loading)
        .fromBottom(true)
        .setCancelable(false)
        .setIsDimEnabled(false)
        .create();
        // 设置Dialog布局里面View的点击事件,文本设置一样
        dialog.setOnClickListener(R.id.dialog_message, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                
            }
        });
        dialog.show();

用起来感觉简单多了,也可以根据UI定制一些APP通用的Dialog。

上一篇下一篇

猜你喜欢

热点阅读