使用Builder模式封装Dialog和PopupWindow

来源:互联网 发布:javascript长度函数 编辑:程序博客网 时间:2024/06/05 17:33

转载请标明出处:
http://blog.csdn.net/hai_qing_xu_kong/article/details/75125971
本文出自:【顾林海的博客】

前言

Builder模式的定义是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,也就是说将构建过程和部件的表示隔离开,用户可以在不知道内部构建细节的情况下,对对象的构造流程进行相应的控制,比如在Android中典型的Builder模式就是AlerDialog.Builder类。本篇文章主要采用Builder模式对Dialog和PopupWindow进行相应的封装,像这种用对话框形式来表示的UI,在大部分的APP中都会使用到,因此,良好的封装可以让使用者使用起来比较方便。


Dialog的封装



这里写图片描述



在封装Dialog时,会使用静态内部类Builder对Diloag的标题、内容、按钮以及事件监听进行配置,并通过CommonDialog类展示,Builder类的结构如下:


这里写图片描述



可以看出这是很典型的Builder模式,在配置参数时返回的是Builder本身,这样的话可以通过链式调用,使代码的可读性大大提高。由于封装的是Dialog,因此,Builder类会去继承Dialog来自定义Dialog。下面贴出完整的Dialog封装类:

package com.glh.getproject.view;import android.app.Dialog;import android.content.Context;import android.os.Bundle;import android.text.TextUtils;import android.view.Gravity;import android.view.View;import android.view.View.OnClickListener;import android.view.WindowManager;import android.widget.TextView;import com.glh.getproject.R;public class CommonDialog {    private Builder mBuilder;    private CommonDialog(Builder builder) {        this.mBuilder = builder;    }    public void show() {        mBuilder.showDialog();    }    public static class Builder extends Dialog implements OnClickListener {        private TextView tv_title;        private TextView tv_left;        private TextView tv_right;        private TextView tv_info;        private DialogListener mDialogListener;        private String title;        private String info;        private String strLeftBtn;        private String strRightBtn;        public interface DialogListener {            void ok();            void cancel();        }        void showDialog() {            show();        }        @Override        protected void onCreate(Bundle savedInstanceState) {            super.onCreate(savedInstanceState);            setContentView(R.layout.dialogl_info_show);            initUI();            initEvent();            initViewStatus();        }        private void initUI() {            tv_title = findViewById(R.id.tv_title);            tv_left = findViewById(R.id.tv_left);            tv_right = findViewById(R.id.tv_right);            tv_info = findViewById(R.id.tv_info);        }        private void initViewStatus() {            if (!TextUtils.isEmpty(title)) {                tv_title.setText(title);            }            if (!TextUtils.isEmpty(info)) {                tv_info.setText(info);            }            if (!TextUtils.isEmpty(strLeftBtn)) {                tv_left.setText(strLeftBtn);            } else {                tv_left.setText("确定");            }            if (!TextUtils.isEmpty(strRightBtn)) {                tv_right.setText(strRightBtn);            } else {                tv_right.setText("取消");            }        }        private void initEvent() {            tv_left.setOnClickListener(this);            tv_right.setOnClickListener(this);        }        @Override        public void onClick(View v) {            switch (v.getId()) {                case R.id.tv_left:                    if (mDialogListener != null) {                        dismiss();                        mDialogListener.ok();                    }                    break;                case R.id.tv_right:                    if (mDialogListener != null) {                        dismiss();                        mDialogListener.cancel();                    }                    break;                default:                    break;            }        }        public Builder(Context context) {            super(context, R.style.MessageBox);            setCanceledOnTouchOutside(false);            getWindow().setBackgroundDrawableResource(android.R.color.transparent);            WindowManager.LayoutParams wl = getWindow().getAttributes();            wl.gravity = Gravity.CENTER;            getWindow().setAttributes(wl);        }        public Builder setListener(DialogListener listener) {            this.mDialogListener = listener;            return this;        }        public Builder setTitle(String title) {            this.title = title;            return this;        }        public Builder setInfo(String info) {            this.info = info;            return this;        }        public Builder setLeftButtonTitle(String title) {            this.strLeftBtn = title;            return this;        }        public Builder setRightButtonTitle(String title) {            this.strRightBtn = title;            return this;        }        public CommonDialog build() {            return new CommonDialog(this);        }    }}



相关的Style:

<style name="MessageBox">    <item name="android:windowNoTitle">true</item>    <item name="android:windowIsFloating">true</item>    <item name="android:windowContentOverlay">@null</item>    <item name="android:layout_gravity">center</item></style>



layout文件:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:background="@android:color/transparent">    <RelativeLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_centerInParent="true"        android:layout_marginLeft="20dp"        android:layout_marginRight="20dp"        android:background="@drawable/dialog_background_shape"        android:paddingLeft="16dp"        android:paddingRight="16dp">        <LinearLayout            android:id="@+id/ll_title"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_centerHorizontal="true"            android:layout_marginTop="20dp"            android:gravity="center_horizontal"            android:orientation="vertical">            <TextView                android:id="@+id/tv_title"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:gravity="center"                android:lineSpacingExtra="2dp"                android:textColor="@color/title"                android:textSize="17sp"                android:visibility="visible" />            <TextView                android:id="@+id/tv_info"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:gravity="center"                android:lineSpacingExtra="2dp"                android:paddingTop="20dp"                android:textColor="@color/title"                android:textSize="17sp"                android:visibility="visible" />        </LinearLayout>        <LinearLayout            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_below="@id/ll_title"            android:layout_centerHorizontal="true"            android:layout_marginTop="25dp"            android:gravity="center"            android:orientation="horizontal"            android:paddingBottom="20dp"            android:visibility="visible">            <TextView                android:id="@+id/tv_left"                android:layout_width="0dp"                android:layout_height="wrap_content"                android:layout_marginRight="5dp"                android:layout_weight="1"                android:background="@drawable/red_button_shape"                android:gravity="center"                android:paddingBottom="7dp"                android:paddingLeft="30dp"                android:paddingRight="30dp"                android:paddingTop="7dp"                android:textColor="@color/white"                android:textSize="14sp"                android:visibility="visible" />            <TextView                android:id="@+id/tv_right"                android:layout_width="0dp"                android:layout_height="wrap_content"                android:layout_marginLeft="5dp"                android:layout_weight="1"                android:background="@drawable/gray_button_shape"                android:gravity="center"                android:paddingBottom="7dp"                android:paddingLeft="30dp"                android:paddingRight="30dp"                android:paddingTop="7dp"                android:textColor="@color/white"                android:textSize="14sp"                android:visibility="visible" />        </LinearLayout>    </RelativeLayout></RelativeLayout>



整个Dialog的布局背景和按钮都是通过自定义Shape来实现的:


dialog_background_shape:

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android">    <solid android:color="@color/white" />    <corners android:radius="10dp" /></shape>



red_button_shape:

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android">    <corners android:radius="5dp" />    <solid android:color="#FA001F" /></shape>



gray_button_shape:

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android">    <corners android:radius="5dp" />    <solid android:color="@color/gray" /></shape>



在Activity中使用:

public void showDialog() {    CommonDialog commonDialog = new CommonDialog.Builder(this)            .setListener(new CommonDialog.Builder.DialogListener() {                @Override                public void ok() {                    Toast.makeText(MainActivity.this, "正在更新...", Toast.LENGTH_SHORT).show();                }                @Override                public void cancel() {                }            }).setTitle("更新通知")            .setInfo("当前版本暂不可用,请下载最新版本,以便享受优质内容。")            .setLeftButtonTitle("知道了")            .setRightButtonTitle("不需要")            .build();    commonDialog.show();}




PopupWindow的封装



这里写图片描述


PopupWindow的封装和Dialog的封装是一样的套路,Builder的结构如下:

这里写图片描述



最后通过PopupWindow的showAtLocation方法显示。

完整的PopupWindow封装代码如下:

package com.glh.getproject.view;import android.content.Context;import android.graphics.drawable.BitmapDrawable;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.PopupWindow;import android.widget.TextView;import com.glh.getproject.R;/** * 更新弹框 * Created by glh on 2017-05-09. */public class UpdateDialog {    private PopupWindow mPopupWindow;    private Builder mBuilder;    private UpdateDialog(Builder builder) {        this.mBuilder = builder;        View mPopupLayout = builder.mPopupLayout;        this.mPopupWindow = new PopupWindow(mPopupLayout, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, true);        this.mPopupWindow.setContentView(mPopupLayout);        this.mPopupWindow.setOutsideTouchable(true);        this.mPopupWindow.setFocusable(true);        this.mPopupWindow.setBackgroundDrawable(new BitmapDrawable());        this.mPopupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {            @Override            public void onDismiss() {                if (mBuilder.mCloseListener != null) {                    mBuilder.mCloseListener.onClose();                }            }        });        this.mPopupWindow.update();    }    public void dismiss() {        if (!mPopupWindow.isShowing()) {            return;        }        mPopupWindow.dismiss();    }    public void showAtLocation(View parent, int gravity, int x, int y) {        mPopupWindow.showAtLocation(parent, gravity, x, y);    }    public static class Builder {        private View mPopupLayout;        private TextView tv_title;        private TextView tv_left;        private TextView tv_right;        private TextView tv_info;        private UpgradeListener mUpgradeListener;        private CloseListener mCloseListener;        private void initEvent() {            tv_left.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View view) {                    if (mUpgradeListener != null) {                        mUpgradeListener.upgrade(true);                    }                }            });            tv_right.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View view) {                    if (mUpgradeListener != null) {                        mUpgradeListener.upgrade(false);                    }                }            });        }        public interface UpgradeListener {            void upgrade(boolean upgrade);        }        public interface CloseListener {            void onClose();        }        public Builder(Context context) {            mPopupLayout = LayoutInflater.from(context).inflate(R.layout.dialogl_info_show, null, true);            tv_title = mPopupLayout.findViewById(R.id.tv_title);            tv_left = mPopupLayout.findViewById(R.id.tv_left);            tv_right = mPopupLayout.findViewById(R.id.tv_right);            tv_info = mPopupLayout.findViewById(R.id.tv_info);            initEvent();        }        public Builder setUpgradeListener(UpgradeListener listener) {            this.mUpgradeListener = listener;            return this;        }        public Builder setCloseListener(CloseListener listener) {            this.mCloseListener = listener;            return this;        }        public Builder setTitle(String title) {            this.tv_title.setText(title);            return this;        }        public Builder setInfo(String info) {            this.tv_info.setText(info);            return this;        }        public Builder setLeftButtonTitle(String title) {            this.tv_left.setText(title);            return this;        }        public Builder setRightButtonTitle(String title) {            this.tv_right.setText(title);            return this;        }        public UpdateDialog build() {            return new UpdateDialog(this);        }    }}



layout文件和Dialog的布局文件一样,这里就不贴出来了。

在Activity的使用:

private UpdateDialog commonDialog;private void showPopupWindow() {    if (null == commonDialog) {        commonDialog = new UpdateDialog.Builder(this)                .setUpgradeListener(new UpdateDialog.Builder.UpgradeListener() {                    @Override                    public void upgrade(boolean upgrade) {                        commonDialog.dismiss();                        if (upgrade) {                            Toast.makeText(MainActivity.this, "正在更新...", Toast.LENGTH_SHORT).show();                        }                    }                }).setCloseListener(new UpdateDialog.Builder.CloseListener() {                    @Override                    public void onClose() {                        Toast.makeText(MainActivity.this, "对话框关闭了", Toast.LENGTH_SHORT).show();                    }                }).setTitle("更新通知")                .setInfo("当前版本暂不可用,请下载最新版本,以便享受优质内容。")                .setLeftButtonTitle("知道了")                .setRightButtonTitle("不需要")                .build();    }    commonDialog.showAtLocation(mGroup, Gravity.CENTER, 0, 0);}




总结



总的来说相同的方法,不同的执行顺序,产生不同的事件结果时,可以考虑采用建造者模式;多个部件或零件,都可以装配到一个对象中,但产生的运行结果又不相同时,可以考虑采用建造者模式;产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,可以考虑采用建造者模式。

原创粉丝点击