java建造者模式在android上的实践

java建造者模式在android上的应用

其中AlertDialog就是一个例子,一般我们会这么用

AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setXXX();
...
builder.create().show();

同理类似的还有Notification.Builder、StringBuilder等等,之前用过的一些第三方SDK都有见到过这种方式

今天心血来潮,项目中有很多地方用到PopupWindow,考虑到样式什么的都不是完全统一的,每次创建的时候有点麻烦,于是乎想到做一个包装类

下边代码注释比较详细就不做解释了,提一点,PopupParams中的apply方法是具体设置PopupWindow的地方,但是其显示要延迟到show方法中去做,自定义填充的view也要抛出来,以便在create之后外部可以拿到view,从中查找到需要的子view对象进行操作

其中封装了比较常用的设置,还有些没有封装到,若需要可以自己扩展

代码实现


  • MyPopupWindow.java
/**
 * Created by yy on 2015/11/20.
 * 自定义PopupWindow
 * 使之以类似AlertDialog的方式建造生成并显示
 */
public class MyPopupWindow extends PopupWindow {
    /**
     * MyPopupWindow的控制类,持有一些必要的引用,同时可以参与控制PopupWindow
     */
    private MyPopupControler mControler;

    /**
     * @param context 必须为Activity
     * @param params  可设置PopupWindow的一些参数,根据需要以后可以扩展{@link PopupParams}
     */
    private MyPopupWindow(Context context, PopupParams params) {
        mControler = new MyPopupControler(((Activity) context).getWindow(), this, params);
    }

    /**
     * 可设置PopupWindow的一些参数,根据需要以后可以扩展
     */
    static class PopupParams {
        /**
         * 在BUilder过程是否设置了动画{@link MyPopupWindow.Builder#setAnimationStyle(int)}
         */
        public boolean hasAnimationStyle = false;

        public Context mContext;

        /**
         * PopupWindow的自定义样式,通常是一个xml资源文件
         */
        public int mLayoutId;

        /**
         * 显示背景,默认全透明
         */
        public Drawable mBackground;

        /**
         * 显示和隐藏的动画样式资源
         */
        public int mAnimationStyle;

        /**
         * {@link PopupWindow#setFocusable(boolean)}
         */
        public boolean mFocusable = true;

        /**
         * {@link PopupWindow#setOutsideTouchable(boolean)}
         */
        public boolean mOutsideTouchable = true;

        /**
         * 默认宽高为包裹内容
         * {@value LayoutParams#WRAP_CONTENT}
         */
        public int mWidth = -99;
        public int mHeight = -99;

        /**
         * 以下为{@link PopupWindow#showAtLocation(View, int, int, int)}的四个参数
         * 其中mParent必须设置或者构造时指定
         * mGravity默认为 {@value Gravity#CENTER}
         * mOffsetX和mOffsetY默认为 0
         */
        public View mParent;
        public int mGravity = Gravity.CENTER;
        public int mOffsetX = 0;
        public int mOffsetY = 0;

        /**
         * 此项为了以后扩展使用LayoutParams而设置
         */
        public WindowManager.LayoutParams mLayoutParams;

        /**
         * 显示PopupWindow时窗口背景的透明度,默认0.7
         * 会覆盖mLayoutParams中的alpha
         */
        public float mAlpha = 0.7f;

        /**
         * PopupWindow消失时回调
         */
        public PopupWindow.OnDismissListener mOnDismissListener;

        public PopupParams(Context context) {
            mContext = context;
        }

        /**
         * 在{@link Builder#create()}时将建造的PopupWindow参数保存应用到{@link MyPopupControler}
         * 以便在{@link MyPopupWindow#show()}使用
         *
         * @param controler 操作对象
         */
        public void apply(MyPopupControler controler) {
            MyPopupWindow popupWindow = controler.getPopupWindow();
            View view = View.inflate(mContext, mLayoutId, null);
            controler.setView(view);
            popupWindow.setContentView(view);
            popupWindow.setWidth(mWidth == -99 ? -2 : DensityUtil.dip2px(mContext, mWidth));
            popupWindow.setHeight(mHeight == -99 ? -2 : DensityUtil.dip2px(mContext, mHeight));
            popupWindow.setBackgroundDrawable(mBackground == null ? new ColorDrawable(Color
                    .TRANSPARENT) : mBackground);
            popupWindow.setFocusable(mFocusable);
            popupWindow.setOutsideTouchable(mOutsideTouchable);
            if (hasAnimationStyle)
                popupWindow.setAnimationStyle(mAnimationStyle);
            popupWindow.setOnDismissListener(mOnDismissListener == null ? new PopupWindow
                    .OnDismissListener() {
                @Override
                public void onDismiss() {
                    mLayoutParams.alpha = 1.0f;
                    ((Activity) mContext).getWindow().setAttributes(mLayoutParams);
                }
            } : mOnDismissListener);
        }
    }

    public static class Builder {
        private Context mContext;
        private PopupParams P;

        public Builder(Context context) {
            mContext = context;
            P = new PopupParams(mContext);
        }

        public Builder(Context context, View parent) {
            mContext = context;
            P = new PopupParams(mContext);
            P.mParent = parent;
        }

        public Builder setLayout(int layoutId) {
            P.mLayoutId = layoutId;
            return this;
        }

        public Builder setBackground(Drawable background) {
            P.mBackground = background;
            return this;
        }

        public Builder setAnimationStyle(int animationStyle) {
            P.mAnimationStyle = animationStyle;
            P.hasAnimationStyle = true;
            return this;
        }

        public Builder setFocusable(boolean focusable) {
            P.mFocusable = focusable;
            return this;
        }

        public Builder setOutsideTouchable(boolean touchable) {
            P.mOutsideTouchable = touchable;
            return this;
        }

        public Builder setWidth(int width) {
            P.mWidth = width;
            return this;
        }

        public Builder setHeight(int height) {
            P.mHeight = height;
            return this;
        }

        public Builder setParent(View parent) {
            P.mParent = parent;
            return this;
        }

        public Builder setGravity(int gravity) {
            P.mGravity = gravity;
            return this;
        }

        public Builder setOffsetX(int offsetX) {
            P.mOffsetX = offsetX;
            return this;
        }

        public Builder setOffsetY(int offsetY) {
            P.mOffsetY = offsetY;
            return this;
        }

        public Builder setLayoutParams(LayoutParams layoutParams) {
            P.mLayoutParams = layoutParams;
            return this;
        }

        public Builder setAlpha(float alpha) {
            P.mAlpha = alpha;
            return this;
        }

        public Builder setOnDismissListener(OnDismissListener listener) {
            P.mOnDismissListener = listener;
            return this;
        }

        public MyPopupWindow create() {
            final MyPopupWindow popupWindow = new MyPopupWindow(mContext, P);
            P.apply(popupWindow.mControler);
            return popupWindow;
        }

        public MyPopupWindow show() {
            MyPopupWindow popupWindow = create();
            popupWindow.showAtLocation(P.mParent, P.mGravity, P.mOffsetX, P.mOffsetY);
            P.mLayoutParams = ((Activity) mContext).getWindow().getAttributes();
            P.mLayoutParams.alpha = P.mAlpha;
            ((Activity) mContext).getWindow().setAttributes(P.mLayoutParams);
            return popupWindow;
        }
    }

    /**
     * @return {@link Builder#create()}填充的自定义view
     * @see PopupParams#apply(MyPopupControler)
     */
    public View getView() {
        if (mControler != null)
            return mControler.getView();
        else
            return null;
    }

    /**
     * 按照既定的参数显示PopupWindow
     *
     * @return 显示的PopupWindow
     */
    public MyPopupWindow show() {
        PopupParams p = mControler.getParams();
        mControler.getPopupWindow().showAtLocation(p.mParent, p.mGravity, p.mOffsetX, p.mOffsetY);
        p.mLayoutParams = mControler.getWindow().getAttributes();
        p.mLayoutParams.alpha = p.mAlpha;
        mControler.getWindow().setAttributes(p.mLayoutParams);
        return mControler.getPopupWindow();
    }
}
  • MyPopupControler.java
public class MyPopupControler {
    /**
     * Activity Window
     */
    private Window mWindow;

    /**
     * 建造PopupWindow的参数
     */
    private PopupParams P;

    /**
     * 要显示的PopupWindow
     */
    private MyPopupWindow mPopupWindow;

    /**
     * 填充PopupWindow的自定义view
     */
    private View mView;

    public MyPopupControler(Window window, MyPopupWindow popupWindow, PopupParams params) {
        mWindow = window;
        P = params;
        mPopupWindow = popupWindow;
    }

    public View getView() {
        return mView;
    }

    public void setView(View view) {
        mView = view;
    }

    public Window getWindow() {
        return mWindow;
    }

    public PopupParams getParams() {
        return P;
    }

    public MyPopupWindow getPopupWindow() {
        return mPopupWindow;
    }
}
  • 应用场景片段

    xml布局文件很简单只有一个TextView可以自己实现就好了,不再贴出了

popupWindow = new MyPopupWindow.Builder(this, parent)
    .setLayout(R.layout.mypopuwindow)
    .setAnimationStyle(R.style.Animation_AppCompat_DropDownUp)
    .setWidth(320)
    .setHeight(240)
    .create();
View view = pwShopNotice.getView();
TextView tvContent = (TextView) view.findViewById(R.id.tv_content);
tvContent.setText("我是PopupWindow");
popupWindow.show();

理论补充:

建造者概念:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示
建造者模式的好处就是使得建造代码与表示代码分离,由于建造者隐藏了“产品”是如何建造的,所以若需要改变一个“产品”的内部表示,只需再定义另一个Builder

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值