1 前言

在我们的日常开发中,对话框是一个常见的组件,例如下面的对话框,分别是三种不同类型的对话框
Android View 高级框架二 Builder模式打造通用对话框_第1张图片Android View 高级框架二 Builder模式打造通用对话框_第2张图片
Android View 高级框架二 Builder模式打造通用对话框_第3张图片

在Android开发中,对话框也和我们的TitleBar一样,有各种样式,而且它比TitleBar更加的复杂,因为对话框显示的位置还有底部显示,中心显示,顶部显示,以及动画等,因此。对于对话框,我们也可以封装以下。这里我们还是采用Builder模式来封装。

封装思路:将UI实现及事件和我们对话框基本属性进行解耦,从而一套对话框框架可以实现多种布局及UI实现。

2 BaseDialog架构图

封装的第一版的对话框架构图如下:
Android View 高级框架二 Builder模式打造通用对话框_第4张图片
BaseDialog:
采用Builder模式来封装,将各种参数都封装到DialogParams这个类中
mParams 主要是对话框在屏幕切换方向后重建时使用的

BaseDialog.Builder:
提供对对话框的各种参数的设置,最后以Builder模式创建对话框。
DialogParams:
对话框参数类,主要包括对话框的宽高,布局方向,是否可取消,内容View以及监听事件等
DialogViewHolder:
辅助类,用于对对话框中的内容View进行简单的Text设置,图片设置,事件设置等
DialogListener:
事件监听器

这个版本目前还不是非常成熟,不过已经能引入项目使用了,后续还有优化的空间。

3 BaseDaialog的设计及实现

先来看BaseDialog.Builder的实现

/**     * 使用builder模式     */    public static class Builder{        private Context mBuilderContext;        /**         * 参数         */        private DialogParams mBuilderParams ;        /**         * helper         */        private DialogViewHolder mHolder;        /**         * 所引用的dialog         */        BaseDialog dialog;        /**         * 构造方法         * @param context         */        public Builder(Context context){            mBuilderContext = context;            dialog = new BaseDialog();            mBuilderParams = new DialogParams();            mHolder = new DialogViewHolder(dialog);            mBuilderParams.mHolder = mHolder;            mBuilderParams.mEventMap.put(TEXT,new HashMap());            mBuilderParams.mEventMap.put(DRAWABLE,new HashMap());            mBuilderParams.mEventMap.put(LISTENER,new HashMap());        }        /**         * 设置setContentView         * @param layoutId         * @return         */        public Builder setContentView(int layoutId){            mBuilderParams.mLayoutId = layoutId;            mBuilderParams.mContentView = LayoutInflater.from(mBuilderContext).inflate(mBuilderParams.mLayoutId,null);            LogManager.i(TAG,"mBuilderParams.mContentView.getParent():" + mBuilderParams.mContentView.getParent());            mBuilderParams.mHolder.setContentView(mBuilderParams.mContentView);            return this;        }        /**         * 设置ContentView         * @param view         * @return         */        public Builder setContentView(View view){            mBuilderParams.mContentView = view;            mBuilderParams.mLayoutId = 0;            mBuilderParams.mHolder.setContentView(mBuilderParams.mContentView);            LogManager.i(TAG,"mBuilderParams.mContentView.getParent():" + mBuilderParams.mContentView.getParent());            return this;        }        /**         * 设置点击对话框外是否可以取消         * @param cancelable         * @return         */        public Builder setCancelable(boolean cancelable){            mBuilderParams.isCancelable = cancelable;            return this;        }        /**         * 设置要显示需要的fragment         * @param manager         * @return         */        public Builder setFragmentManager(FragmentManager manager){            mBuilderParams.mFragmentManager = manager;            return this;        }        /**         * 全部宽度显示         * @return         */        public Builder fullWidth(){            mBuilderParams.mWidth = ViewGroup.LayoutParams.MATCH_PARENT;            return this;        }        /**         * 设置位置 居中 底部 顶部         * @param gravity         * @return         */        public Builder setGravity(int gravity){            mBuilderParams.mGravity = gravity;            return this;        }        /**         * 设置内容         * @param viewId         * @param text         */        public Builder setText(int viewId, CharSequence text) {            LogManager.i(TAG,"setText viewId : " + viewId + ",text :" + text);            mBuilderParams.mEventMap.get(TEXT).put(viewId,text);            mBuilderParams.mHolder.setText(viewId,text);            return this;        }        /**         * 设置ImageView         * @param viewId         * @param bitmap         */        public Builder setImage(int viewId, Bitmap bitmap) {            LogManager.i(TAG,"setImage viewId : " + viewId + ",bitmap :" + bitmap);            mBuilderParams.mEventMap.get(DRAWABLE).put(viewId,bitmap);            mBuilderParams.mHolder.setImage(viewId,bitmap);            return this;        }        /**         * 设置ImageView的Drawable         * @param viewId         * @param resId         */        public Builder setDrawable(int viewId, int resId) {            LogManager.i(TAG,"setDrawable viewId : " + viewId + ",resId :" + resId);            mBuilderParams.mEventMap.get(DRAWABLE).put(viewId,resId);            Drawable drawable ;            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){                drawable = mBuilderContext.getDrawable(resId);            }else {                drawable = mBuilderContext.getResources().getDrawable(resId);            }            mBuilderParams.mHolder.setDrawable(viewId,drawable);            return this;        }        /**         * 设置ImageView的Drawable         * @param viewId         * @param drawable         */        @Deprecated        public Builder setDrawable(int viewId, Drawable drawable) {            LogManager.i(TAG,"setDrawable viewId : " + viewId + ",drawable :" + drawable);            mBuilderParams.mHolder.setDrawable(viewId,drawable);            return this;        }        /**         * 设置点击事件         *         * @param viewId         * @param listener         */        public Builder setDialogListener(int viewId, DialogListener listener) {            LogManager.i(TAG,"setOnClickListener viewId : " + viewId + ",listener :" + listener);            mBuilderParams.mEventMap.get(LISTENER).put(viewId,listener);            mBuilderParams.mHolder.setOnClickListener(viewId,listener);            return this;        }        /**         * 创建对话框         * @return         */        public BaseDialog build(){            dialog.mParams = mBuilderParams;            return dialog;        }    }

Builder主要提供各种设置各种参数接口给外部,其他的没有什么特别的

接下来看:DialogParams

/** * @author Created by qiyei2015 on 2017/5/13. * @version: 1.0 * @email: 1273482124@qq.com * @description: Dialog的控制类,控制其中的ContentView等的操作 */public class DialogParams implements Serializable{    /**     * Dialog辅助类     */    public DialogViewHolder mHolder;    /**     * 显示DialogFragment需要的FragmentManager     */    public FragmentManager mFragmentManager;    /**     * 宽度     */    public int mWidth = ViewGroup.LayoutParams.WRAP_CONTENT;    /**     * 动画     */    public int mAnimations = 0;    /**     * 位置     */    public int mGravity = Gravity.CENTER;    /**     * 高度     */    public int mHeight = ViewGroup.LayoutParams.WRAP_CONTENT;    /**     * 内容View     */    public View mContentView;    /**     * 内容布局id     */    public int mLayoutId;    /**     * 是否可以取消     */    public boolean isCancelable;    /**     * 记录事件的map,这里的事件包括setText,D监听器,图片等     */    public Map> mEventMap = new HashMap<>();    @Override    public String toString() {        return "DialogParams{" +                "mHolder=" + mHolder +                ", mFragmentManager=" + mFragmentManager +                ", mWidth=" + mWidth +                ", mAnimations=" + mAnimations +                ", mGravity=" + mGravity +                ", mHeight=" + mHeight +                ", mContentView=" + mContentView +                ", mLayoutId=" + mLayoutId +                ", isCancelable=" + isCancelable +                '}';    }}

主要是对话框的,宽,高,布局位置,布局文件及内容View,是否可取消等

接下来看DialogViewHolder

/** * @author Created by qiyei2015 on 2017/5/13. * @version: 1.0 * @email: 1273482124@qq.com * @description: Dialog辅助类 */public class DialogViewHolder {    private static final String TAG = DialogViewHolder.class.getSimpleName();    /**     * 所引用的dialog     */    private BaseDialog mDialog;    /**     * 内容view     */    private View mContentView;    /**     * contentView中的view集合,使用弱引用,防止内存泄漏     */    private SparseArray> mViews;    public DialogViewHolder(BaseDialog dialog){        mViews = new SparseArray<>();        mDialog = dialog;    }    /**     * 根据id获取对应的view     * @param viewId     * @param      * @return     */    public  T getView(int viewId){        WeakReference viewWeakReference = mViews.get(viewId);        View view = null;        if (viewWeakReference != null){            view = viewWeakReference.get();        }        if (view == null){            view = mContentView.findViewById(viewId);            if (view != null){                mViews.put(viewId,new WeakReference(view));            }        }        return (T) view;    }    /**     * 设置文本内容     * @param viewId     * @param text     */    public void setText(int viewId,CharSequence text){        TextView tv = getView(viewId);        LogManager.i(TAG,"setText tv : " + tv + ",text:" + text);        if (tv != null){            tv.setText(text);            LogManager.i(TAG,"setText tv.getText --> " + tv.getText().toString());        }    }    /**     * 设置ImageView的图片     * @param viewId     * @param bitmap     */    public void setImage(int viewId, Bitmap bitmap){        View view = getView(viewId);        LogManager.i(TAG,"setImage view : " + view + ",bitmap:" + bitmap);        if (view != null && view instanceof ImageView){            ((ImageView)view).setImageBitmap(bitmap);        }        //如果drawable不为null,应该让view显示出来        if (bitmap != null){            view.setVisibility(View.VISIBLE);        }    }    /**     * 设置Drawable     * @param viewId     * @param drawable     */    public void setDrawable(int viewId, Drawable drawable){        View view = getView(viewId);        LogManager.i(TAG,"setDrawable view : " + view + ",resId:" + drawable);        if (view == null){            return;        }        //如果drawable不为null,应该让view显示出来        if (drawable != null){            view.setVisibility(View.VISIBLE);        }        //如果是ImageView就设置图片,否则就设置View背景        if (view instanceof ImageView){            ((ImageView)view).setImageDrawable(drawable);        }else {            view.setBackground(drawable);        }    }    /**     * 给某个view设置点击事件     * @param viewId     * @param listener     */    public void setOnClickListener(int viewId, final DialogListener listener){        View view = getView(viewId);        LogManager.i(TAG,"setOnClickListener view : " + view + ",listener:" + listener);        if (view != null){            view.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    listener.onClick(v);                    mDialog.dismiss();                }            });        }    }    /**     * @return {@link #mContentView}     */    public View getContentView() {        return mContentView;    }    /**     * @param contentView the {@link #mContentView} to set     */    public void setContentView(View contentView) {        mContentView = contentView;    }}

这里使用了弱引用,防止内存泄漏

好,最后来看看BaseDialog的实现:

/** * @author Created by qiyei2015 on 2017/5/13. * @version: 1.0 * @email: 1273482124@qq.com * @description: */public class BaseDialog extends DialogFragment {    /**     * 调试标志     */    private static final String TAG = BaseDialog.class.getSimpleName();    /**     * context     */    protected Context mContext;    /**     * Dialog的参数     */    protected DialogParams mParams;    /**     * onSaveInstanceState保存的key     */    private static final String KEY = "dialog";    /**     * Text的key     */    private static final String TEXT = "text";    /**     * Drawable的key     */    private static final String DRAWABLE = "drawable";    /**     * Listener的Key     */    private static final String LISTENER = "listener";    /**     * 是否是恢复的数据     */    private boolean isSavedInstanceState = false;    /**     * 构造方法     */    public BaseDialog(){        super();    }    @Override    public void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setStyle(DialogFragment.STYLE_NORMAL, R.style.dialog);        //保存数据,防止重建Dialog时出现数据丢失的情况        if (savedInstanceState != null){            mParams = (DialogParams) savedInstanceState.getSerializable(KEY);            LogManager.i(TAG,"savedInstanceState mParams:" + mParams.toString());            isSavedInstanceState = true;        }        setCancelable(mParams.isCancelable);        LogManager.i(TAG,"onCreate()");    }    @Override    public void onSaveInstanceState(Bundle outState) {        super.onSaveInstanceState(outState);        outState.putSerializable(KEY,mParams);    }    @Nullable    @Override    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {        LogManager.i(TAG,"onCreateView()");        //去除标题        getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);        //必须返回的View是Builder中已经设置的那个对象,使用LayoutInflater加载的是另外一个对象        View contentView = mParams.mContentView;        if (savedInstanceState != null){            contentView = LayoutInflater.from(getContext()).inflate(mParams.mLayoutId,null);            mParams.mContentView = contentView;        }        LogManager.i(TAG,"contentView.getParent():" + contentView.getParent());        return contentView;    }    @Override    public void onStart() {        super.onStart();        //设置布局属性        Window window = getDialog().getWindow();        window.setLayout(mParams.mWidth,mParams.mHeight);        window.setGravity(mParams.mGravity);        LogManager.i(TAG,"onStart()");        if (!isSavedInstanceState){            return;        }        HashMap hashMap = mParams.mEventMap.get(TEXT);        for (Map.Entry entry : hashMap.entrySet()){            TextView view = (TextView) mParams.mContentView.findViewById(entry.getKey());            view.setText((CharSequence) entry.getValue());        }        hashMap = mParams.mEventMap.get(DRAWABLE);        for (Map.Entry entry : hashMap.entrySet()){            ImageView view = (ImageView) mParams.mContentView.findViewById(entry.getKey());            view.setVisibility(View.VISIBLE);            if (entry.getValue() instanceof Integer){                view.setImageResource((Integer) entry.getValue());            }else if (entry.getValue() instanceof Bitmap){                view.setImageBitmap((Bitmap) entry.getValue());            }        }        hashMap = mParams.mEventMap.get(LISTENER);        for (final Map.Entry entry : hashMap.entrySet()){            View view = mParams.mContentView.findViewById(entry.getKey());            view.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    ((DialogListener) entry.getValue()).onClick(v);                    dismiss();                }            });        }    }    //略过Builder定义    /**     * 根据id获取对应的view     * @param viewId     * @param      * @return     */    public  T getView(int viewId){        return mParams.mHolder.getView(viewId);    }    /**     * 显示对话框     */    public void show(){        //如果没有被添加        if (!isAdded()){            FragmentTransaction transaction = mParams.mFragmentManager.beginTransaction();            transaction.add(this, TAG);            transaction.commitAllowingStateLoss();        }        LogManager.i(TAG,"show()");    }    /**     * 取消显示对话框     */    @Override    public void dismiss(){        super.dismiss();    }}

没啥好说的,就是注意做了一个在屏幕旋转时恢复对话框参数的动作

目前第一版设计就是这样了,详细的代码参考我的github
https://github.com/qiyei2015/EssayJoke SDK 下的dialog目录

4 BaseDialog应用实例

BaseDialog的使用很简单,下面有两个例子:

BaseDialog dialog = new BaseDialog.Builder(this)                .setCancelable(true)                //.setContentView(R.layout.dialog_test)                .setContentView(R.layout.dialog_test)                .setText(R.id.dialog_content,"这是一个对话框,哈哈哈!")                .setDialogListener(R.id.dialog_ok, new DialogListener() {                    @Override                    public void onClick(View v) {                        ToastUtil.showLongToast("对话框点击了确认");                    }                })                .setDialogListener(R.id.dialog_cancel, new DialogListener() {                    @Override                    public void onClick(View v) {                        ToastUtil.showLongToast("对话框点击了取消");                    }                })//                .setGravity(Gravity.BOTTOM)//                .fullWidth()                .setFragmentManager(getSupportFragmentManager())                .build();        dialog.show();

效果如下:

例子2:

        BaseDialog dialog = new BaseDialog.Builder(this)                .setCancelable(true)                .setContentView(R.layout.common_dialog)                //.setContentView(contentView)                .setText(R.id.id_dialog_title,"这是一个对话框标题!")                .setText(R.id.id_tv_content,"对话框内容")                .setText(R.id.id_tv_confirm,"确认")                .setText(R.id.id_tv_cancel,"取消")                .setDrawable(R.id.id_dialog_title_imv,R.drawable.icon_login_single)                .setDialogListener(R.id.id_tv_confirm, new DialogListener() {                    @Override                    public void onClick(View v) {                        ToastUtil.showLongToast("对话框点击了确认");                    }                })                .setDialogListener(R.id.id_tv_cancel, new DialogListener() {                    @Override                    public void onClick(View v) {                        ToastUtil.showLongToast("对话框点击了取消");                    }                })//                .setGravity(Gravity.BOTTOM)//                .fullWidth()                .setFragmentManager(getSupportFragmentManager())                .build();        dialog.show();

效果如下:

后续再对该框架进行优化

更多相关文章

  1. [android盈利模式探索]我也分享一下我Android的收入数据
  2. 在Android中分享内容到微信
  3. android webview设置内容的字体大小
  4. android内容提供者ContentProvider,UriMatcher和内容观察者Conte
  5. android菜单和对话框
  6. Android获取指定URL的内容
  7. [Android]取得Dialog中EditText的内容问题
  8. Android之博客案例 及 获取指定URL的网页内容

随机推荐

  1. 访问和更改关系数据,使用MSSQL外联接
  2. 在SQL Server数据库中为标识(IDENTITY)列
  3. Microsoft SQLServer的版本区别及选择
  4. 更改SQL Server更改当前数据库的所有者:s
  5. 设定sql server定期自动备份数据库
  6. xp_cmdshell开启与关闭
  7. 如何恢复数据库备份到一个已存在的正在使
  8. 如何强制删除或恢复SQLServer正在使用的
  9. 清除SQLServer日志的两种方法
  10. SQL Server连接失败错误及解决第1/5页