builder设计模式学习及应用dialogfragment链式调用封装

          最近在做视频播放和直播项目,等项目写完了会将视频方面的东西整理出来。今天整理总结一下安卓设计模式中的builder设计模式。

  首先我们看看安卓中最典型的builder设计模式是如何使用的:

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setCustomTitle(titleView);
        builder.setNegativeButton("取消", onClickListener);
        builder.setPositiveButton("确定", onClickListener);
        //...设置一些其他属性值
        builder.create().show();
这个dialog就是安卓系统用builder设计模式给我封装的最典型的一个应用。那么为什么要用builder设计模式呢?网上的解释基本上就是:将一个复杂的对象的构建与他的表示分离,使得同样的构建构成可以创建不同的表示。理解了半天,云里雾里!我的理解就是我们去创建一个有很多属性值得对象的时候,不去直接通过它的构造器创建,而是先去创建一个builder(其实名字叫什么无所谓),然后给builder设置你想要创建对象的属性值,这样间接地来创建对象。这样的好处就是清晰明了,你需要什么、关心什么属性值就给他赋值,不关心的可以完全不用理睬。

我们如何使用builder模式呢?下面通过一个简单的小例子来写一个我们自己的builder模式:

    public class Person {
        private String mName;
        private int mAge;

        /**
         * 一个构造器
         *
         * @param name
         * @param age
         */
        public Person(String name, int age) {
            this.mName = name;
            this.mAge = age;
        }

        /**
         * get set方法,需要就写,不需要就不写
         *
         * @return
         */
        public String getName() {
            return mName;
        }

        public void setName(String name) {
            this.mName = name;
        }

        /**
         * 静态内部类builder
         */
        static class Builder {
            private String mName;
            private int mAge;

            public Builder setName(String name) {
                this.mName = name;
                return this;
            }

            public Builder setAge(int age) {
                this.mAge = age;
                return this;
            }

            public Person create() {
                return new Person(mName, mAge);
            }
        }
    }
         这里只是给了两个属性,一个最简单的builder模式例子写完了,下面来看如何使用:       

     Person person = new Person.Builder()
                .setAge(12)
                .setName("王")
                .create();
至此,一个最简单的builder设计、使用就结束了,自己动手敲一遍发现,原来如此简单,然后我们再来总结一下几个步骤:

 1.创建一个静态内部类builder
 2.将外部类的所有属性都复制一份到内部类中
 3.静态内部类中写设置属性值的set方法,并且每次都将自己返回
 4.静态内部类中写一个方法create创建外部类的实例并返回


应用:学习了就要使用,安卓原生alertdailg封装的固然非常完美,但是如果我们使用上面的方法去创建的话,样式显示在不同的api上会有很大的差别的,特别是在低版本api中样式特别丑,所以项目中基本上很少使用默认样式,而是会选择自定义样式,另外就是在fragment出来不久后谷歌就给出了dialogfragment,然后建议开发人员使用dialogfragment替代alertdialog,具体有什么好处,为什么 我也没有深究过。但是在使用dialogfragment过程中,会有很多需要注意的细节,每次都需要特别注意,而且每次都为了一个效果调试半天,所以正好借助builder模式,我们自己来封装一下:

        先看效果:

                    


当然前两张不是使用的封装代码实现的,而是使用dialogfragment内部dialog实现的。第三张、第四张其实是有出现和退出动画效果的,只是我不会制作gif图。第三张其实我们我们要实现的效果就是可以改变位置、大小、样式等,第四张我想展示的效果就是内部可以嵌套viewpager等等实现各种效果,最后一张是测试的,也贴出来了。看一眼链式调用使用方法吧:

      CustomDialogFragment.Builder.getInstance()
                .setResId(R.layout.layout_one)
                .setAnimationId(R.style.dialog_animation)
                .setOnRootViewReadyListener(new CustomDialogFragment.Builder.OnRootViewReadyListener() {
                    @Override
                    void rootView(View view, Bundle savedInstanceState, final DialogFragment dialog) {
                        view.findViewById(R.id.one).setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                dialog.dismiss();
                            }
                        });
                        view.findViewById(R.id.two).setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                dialog.dismiss();
                            }
                        });
                    }
                })
                .show(getFragmentManager());
        是不是很简单,当然可以设置很多属性,这里仅仅展示了几个。最后将源码贴出来,不过多解释,各个属性值得参数含义都有注解,注意的地方就是各个参数在fragment中生命周期中设置的位置,否则会出现没有效果的问题。

        

/**
 * Created by zhq on 2017/12/1.
 */

public class CustomDialogFragment extends DialogFragment {
    private static final int NO_SET_DATA = -1;
    private static final String LAYOUT_RES_ID = "res_id";
    private static final String CUSTOME_STYLE = "style";
    private static final String DIALOG_WIDTH = "width";
    private static final String DIALOG_HEIGHT = "height";
    private static final String DIALOG_GRAVITY = "gravity";
    private static final String DIALOG_DIMAMOUNT = "amount";
    private static final String DIALOG_NO_TITLE = "no_title";
    private static final String DIALOG_GET_ROOTVIEW = "no_title";
    private static final String DIALOG_STATE_BAR_TRANSLATE = "bar_translate";
    private static final String DIALOG_CANCLEABLE = "cancle";
    private static final String DIALOG_CANCLEABLE_OUTSIDE = "cancle_outside";
    private static final String DIALOG_ANIMATION = "animation";


    private static CustomDialogFragment getInstance(int resId, int styleId, int width, int height, int gravity,
                                                    float dimamount, boolean notitle, boolean stateBarTranslate, boolean cancleAble,
                                                    boolean canceledOnTouchOutside, int animationId, Builder.OnRootViewReadyListener listener) {
        CustomDialogFragment fragment = new CustomDialogFragment();
        Bundle bundle = new Bundle();
        bundle.putInt(LAYOUT_RES_ID, resId);
        bundle.putInt(CUSTOME_STYLE, styleId);
        bundle.putInt(DIALOG_WIDTH, width);
        bundle.putInt(DIALOG_HEIGHT, height);
        bundle.putInt(DIALOG_GRAVITY, gravity);
        bundle.putFloat(DIALOG_DIMAMOUNT, dimamount);
        bundle.putBoolean(DIALOG_NO_TITLE, notitle);
        bundle.putParcelable(DIALOG_GET_ROOTVIEW, listener);
        bundle.putBoolean(DIALOG_STATE_BAR_TRANSLATE, stateBarTranslate);
        bundle.putBoolean(DIALOG_CANCLEABLE, cancleAble);
        bundle.putBoolean(DIALOG_CANCLEABLE_OUTSIDE, canceledOnTouchOutside);
        bundle.putInt(DIALOG_ANIMATION, animationId);
        fragment.setArguments(bundle);
        return fragment;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        int styleId = getArguments().getInt(CUSTOME_STYLE, -1);
        if (NO_SET_DATA != styleId) {
            setStyle(DialogFragment.STYLE_NORMAL, styleId);
        }
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        //getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.RED));
        Bundle bundle = getArguments();
        if (bundle.getBoolean(DIALOG_NO_TITLE)) {
            getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
        }
        float dimamount = bundle.getFloat(DIALOG_DIMAMOUNT);
        if (-1.0f != dimamount) {
            getDialog().getWindow().setDimAmount(dimamount);//设置背景颜色
        }
        if (bundle.getBoolean(DIALOG_STATE_BAR_TRANSLATE, false)) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                getDialog().getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            }
        }
        if (NO_SET_DATA != bundle.getInt(DIALOG_ANIMATION)) {
            getDialog().getWindow().setWindowAnimations(bundle.getInt(DIALOG_ANIMATION));
        }
        View inflate = inflater.inflate(getArguments().getInt(LAYOUT_RES_ID), container, false);
        AutoUtils.autoSize(inflate);
        return inflate;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        Builder.OnRootViewReadyListener listener = getArguments().getParcelable(DIALOG_GET_ROOTVIEW);
        if (null != listener) {
            listener.rootView(view, savedInstanceState, this);
        }
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Bundle arguments = getArguments();
        int width = arguments.getInt(DIALOG_WIDTH);
        int height = arguments.getInt(DIALOG_HEIGHT);
        int gravity = arguments.getInt(DIALOG_GRAVITY);
        if (-3 != (width + height + gravity)) {
            Window dialogWindow = getDialog().getWindow();
            WindowManager.LayoutParams lp = dialogWindow.getAttributes();
            if (NO_SET_DATA != width) {
                lp.width = width;
            }
            if (NO_SET_DATA != height) {
                lp.height = height;
            }
            if (NO_SET_DATA != gravity) {
                lp.gravity = gravity;
            }
            dialogWindow.setAttributes(lp);
        }
        getDialog().setCancelable(arguments.getBoolean(DIALOG_CANCLEABLE));
        getDialog().setCanceledOnTouchOutside(arguments.getBoolean(DIALOG_CANCLEABLE_OUTSIDE));
    }

    @Override
    public void show(FragmentManager manager, String tag) {
        if (!this.isAdded()) {
            manager.beginTransaction().add(this, tag).commitAllowingStateLoss();
        }
    }

    @Override
    public void dismiss() {
        super.dismissAllowingStateLoss();
    }

    public static class Builder {
        /**
         * 设置页面布局文件id
         */
        private int resId;
        /**
         * 设置显示样式,可以在样式中设置动画等等
         */
        private int styleId = -1;
        /**
         * 设置高度
         */
        private int height = -1;
        /**
         * 设置宽度
         */
        private int width = -1;
        /**
         * 设置显示的位置
         */
        private int gravity = -1;
        /**
         * 设置背景透明度
         */
        private float dimAmount = 0.6f;
        /**
         * 是否为没有标题
         */
        private boolean notitile = true;
        /**
         * 处理4.4以上手机全屏时状态栏变黑
         */
        private boolean stateBarTranslate = true;
        /**
         * 点击返回键是否消失
         */
        private boolean cancleAble = true;
        /**
         * 点击返回键是否消失
         */
        private int animationId = -1;
        /**
         * 触摸弹框外部区域是否消失
         */
        private boolean canceledOnTouchOutside = true;
        /**
         * 设置消失事件监听
         */
        private OnDilogDisssmissListener dissListener;
        /**
         * 拿到页面根view
         */
        private OnRootViewReadyListener rootViewReadyListener;

        public static Builder getInstance() {
            return new Builder();
        }

        public void show(FragmentManager fragmentManager) {
            CustomDialogFragment dialogFragment = CustomDialogFragment.getInstance(resId, styleId, width, height, gravity, dimAmount,
                    notitile, stateBarTranslate, cancleAble, canceledOnTouchOutside, animationId, rootViewReadyListener);
            if (null != dissListener) {
                dialogFragment.getDialog().setOnDismissListener(new DialogInterface.OnDismissListener() {
                    @Override
                    public void onDismiss(DialogInterface dialog) {
                        dissListener.onDissmisss();
                    }
                });
            }
            dialogFragment.show(fragmentManager, "");
        }

        public Builder setResId(int resId) {
            this.resId = resId;
            return this;
        }

        public Builder setAnimationId(int animationId) {
            this.animationId = animationId;
            return this;
        }

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

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

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

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

        public Builder setDimAmount(float dimAmount) {
            this.dimAmount = dimAmount;
            return this;
        }

        public Builder setNoTitle(boolean notitle) {
            this.notitile = notitle;
            return this;
        }

        public Builder setOnDilogDisssmissListener(OnDilogDisssmissListener listener) {
            this.dissListener = listener;
            return this;
        }

        public Builder setOnRootViewReadyListener(OnRootViewReadyListener listener) {
            this.rootViewReadyListener = listener;
            return this;
        }

        public Builder setStateBarTranslate(boolean stateBarTranslate) {
            this.stateBarTranslate = stateBarTranslate;
            return this;
        }

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

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

        interface OnDilogDisssmissListener {
            void onDissmisss();
        }

        public static abstract class OnRootViewReadyListener implements Parcelable {
            public abstract void rootView(View view, Bundle savedInstanceState, DialogFragment dialog);

            @Override
            public int describeContents() {
                return 0;
            }

            @Override
            public void writeToParcel(Parcel dest, int flags) {
            }
        }
    }
}

    最后,如果项目中有很多例如退出啊等等需要用户确认的弹框,其实另一种封装个人觉得更简单,代码就不贴了自行下载吧,看看效果和使用:

    

    使用方法:

    

    NormalDialogFragment instance = NormalDialogFragment.getInstance("确定退出吗?", "确定", "取消");
        instance.setOnPositiveClickListener(new NormalDialogFragment.OnPositiveClickListener() {
            @Override
            public void onPositiveClickListen() {
                //退出
            }
        });
        instance.show(getSupportFragmentManager(), "");
   NormalDialogFragment instance = NormalDialogFragment.getInstance("确定退出吗?", "退出后将丢失重要文件");
        instance.setOnPositiveClickListener(new NormalDialogFragment.OnPositiveClickListener() {
            @Override
            public void onPositiveClickListen() {
                //退出
            }
        });
        instance.show(getSupportFragmentManager(), "");
有需要的自行下载源码吧:
github地址: https://github.com/zhq217217/builder-dialogfragment

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值