Builder设计模式--NavigationBar的实现

在应用程序中肯定会有标题栏,一般就是左边一个返回,一个标题,右边一个图片或者文字,不过有时候也会碰到中间是搜索框的情况,实现方式也很多,自定view、include、直接在xml布局中通过findViewById写等方式;这里是采用Builder设计模式打造一个NavigationBar,不需要在xml布局中去写,在activity初始化标题或者控件的地方实例一个NavigationBar对象并设置相应的参数就可以了。

Builder设计模式是一种比较常见的设计模式,Dialog等源码,Okhttp等第三方框架中都有使用到;

Builder设计模式又称为建造者模式,将建造过程与表示过程相分离,让(参数)构建过程变得更加简单和直观。

在Builder设计模式中普遍会采用链式调用的方式,但是需要注意,链式调用并不是Builder设计模式,链式调用这是一种调用方式;链式调用有一个体现,就是在调用方法的时候返回自身对象,Builder 一般也有一种体现,就是一般都会出现 Builder 对象。

Builder设计模式--NavigationBar的实现_第1张图片

创建一个接口,接口提供一个创建NavigationBar、绑定参数、添加到布局中的方法,让构造类去实现它;

public interface INavigation {
    /**
     * 创建navigationbar
     */
    void createNavigationBar();

    /**
     * 绑定navigationbar参数
     */
    void attachNavigationParmas();

    /**
     * 将navigationBar添加到父布局中
     * @param navigationView
     * @param parent
     */
    void attachParent(View navigationView, ViewGroup parent);
}
public class AbsNavigationBar implements INavigation {
    private T mBuilder;
    private View mNavigationView;

    protected AbsNavigationBar(T builder) {
        this.mBuilder = builder;
        createNavigationBar();
    }

    @Override
    public void createNavigationBar() {
        mNavigationView = LayoutInflater.from(mBuilder.mContext).inflate(mBuilder.mLayoutId, mBuilder.mParent, false);
        //添加
        attachParent(mNavigationView, mBuilder.mParent);
        //添加参数
        attachNavigationParmas();
    }

    @Override
    public void attachNavigationParmas() {
        Map textMap = mBuilder.textMap;
        for(Map.Entry texts:textMap.entrySet()){
            TextView textView = findViewById(texts.getKey());
            textView.setText(texts.getValue());
        }
        Map clicks = mBuilder.clicks;
        for(Map.Entry click:clicks.entrySet()){
            View view = findViewById(click.getKey());
            view.setOnClickListener(click.getValue());
        }
    }

    public  T findViewById(int viewId) {
        return (T) mNavigationView.findViewById(viewId);
    }

    /**
     * 返回 Builder
     *
     * @return
     */
    public T getBuilder() {
        return mBuilder;
    }

    @Override
    public void attachParent(View navigationView, ViewGroup parent) {
        parent.addView(navigationView, 0);
    }

    public static abstract class Builder {
        public Context mContext;
        public int mLayoutId;
        public ViewGroup mParent;
        //存储对应id的文本
        public Map textMap;
        //存储对应id的点击事件
        public Map clicks;

        public Builder(Context context, int layoutId) {
            this.mContext = context;
            this.mLayoutId = layoutId;
            Activity activity = (Activity) context;
            ViewGroup viewGroup = (ViewGroup) activity.getWindow().getDecorView();
            this.mParent = (ViewGroup) viewGroup.getChildAt(0);
            textMap = new HashMap<>();
            clicks = new HashMap<>();
        }

        /**
         * 设置左边文字
         *
         * @param leftId
         * @param leftText
         * @return
         */
        public T setLeftText(int leftId, String leftText) {
            textMap.put(leftId, leftText);
            return (T) this;
        }

        /**
         * 设置中间文字
         *
         * @param middleId
         * @param middleText
         * @return
         */
        public T setMiddleText(int middleId, String middleText) {
            textMap.put(middleId, middleText);
            return (T) this;
        }

        /**
         * 设置右边文字
         *
         * @param rightId
         * @param rightText
         * @return
         */
        public T setRightText(int rightId, String rightText) {
            textMap.put(rightId, rightText);
            return (T) this;
        }

        /**
         * 左边点击事件
         *
         * @param leftId
         * @param listener
         * @return
         */
        public T setLeftClick(int leftId, View.OnClickListener listener) {
            clicks.put(leftId, listener);
            return (T) this;
        }

        /**
         * 右边点击事件
         *
         * @param rightId
         * @param listener
         * @return
         */
        public T setRightClick(int rightId, View.OnClickListener listener) {
            clicks.put(rightId, listener);
            return (T) this;
        }

        /**
         * 用来创建 NavigationBar
         *
         * @return
         */
        public abstract AbsNavigationBar create();
    }
}

在Builder构造方法中通过上下文强转成Activity,通过当前的Activity获取到DecorView将NavigationBar添加到DecorView布局容器中,这样就不需要在使用Activity中取进行添加;Builder中提供一些设置参数的方法,在attachNavigationParmas方法中进行参数的绑定;因为Builder是一个静态抽象类,所以在使用的时候要定义一个具体的NavigationBar继承自AbsNavigationBar;

public class NavigationBar extends AbsNavigationBar{
    protected NavigationBar(Builder builder) {
        super(builder);
    }
    public static class Builder extends AbsNavigationBar.Builder{

        public Builder(Context context, int layoutId) {
            super(context, layoutId);
        }

        @Override
        public NavigationBar create() {
            return new NavigationBar(this);
        }
    }
}

这样就构建好了,实例化一个NavigationBar对象并设置相应的参数;

NavigationBar navigationBar=new NavigationBar.Builder(this,R.layout.navigation_layout)
                .setLeftText(R.id.tv_left,"返回")
                .setMiddleText(R.id.tv_title,"首页")
                .setRightText(R.id.tv_right,"保存")
                .setLeftClick(R.id.tv_left, new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Toast.makeText(MainActivity.this,"返回",Toast.LENGTH_LONG).show();
                    }
                })
                .setRightClick(R.id.tv_right, new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Toast.makeText(MainActivity.this,"保存",Toast.LENGTH_LONG).show();
                    }
                })
                .create();

这样就创建了一个NavigationBar,但是在每次设置参数的时候都需要传入一个对应的控件id,还是蛮繁琐的,可以根据项目的需要创建一个公用的NavigationBar,如果差异比较大的话,根据当前页面的需求有选择的创建对应的NavigationBar;

public class DefaultNavigationBar extends AbsNavigationBar{
    protected DefaultNavigationBar(Builder builder) {
        super(builder);
    }

    @Override
    public void attachNavigationParmas() {
        super.attachNavigationParmas();
        //绑定参数
    }

    public static class Builder extends AbsNavigationBar.Builder{
        public Builder(Context context) {
            super(context, R.layout.navigation_layout);
        }

        @Override
        public DefaultNavigationBar create() {
            return new DefaultNavigationBar(this);
        }
        /**
         * 设置左边文字
         *
         * @param leftText
         * @return
         */
        public Builder setLeftText(String leftText) {
            if(leftText==null||leftText.length()==0){
                leftText="返回";
            }
            setLeftText(R.id.tv_left,leftText);
            return this;
        }

        /**
         * 设置中间文字
         *
         * @param middleText
         * @return
         */
        public Builder setMiddleText(String middleText) {
            setMiddleText(R.id.tv_title,middleText);
            return this;
        }

        /**
         * 设置右边文字
         *
         * @param rightText
         * @return
         */
        public Builder setRightText(String rightText) {
            setRightText(R.id.tv_right,rightText);
            return this;
        }

        /**
         * 左边点击事件
         *
         * @param listener
         * @return
         */
        public Builder setLeftClick(View.OnClickListener listener) {
            setLeftClick(R.id.tv_left,listener);
            return this;
        }

        /**
         * 右边点击事件
         *
         * @param listener
         * @return
         */
        public Builder setRightClick(View.OnClickListener listener) {
            setRightClick(R.id.tv_right,listener);
            return this;
        }
    }
}

这样子实例化NavigationBar时就不需要每次都传入一个控件id;

DefaultNavigationBar navigationBar=new DefaultNavigationBar.Builder(this)
                .setMiddleText("首页")
                .setRightText("保存")
                .setLeftClick(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Toast.makeText(MainActivity.this,"返回",Toast.LENGTH_LONG).show();
                    }
                })
                .setRightClick(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Toast.makeText(MainActivity.this,"保存",Toast.LENGTH_LONG).show();
                    }
                })
                .create();

如果需要对NavigationBar中的一些特殊的控件做处理,可以通过实例化好的NavigationBar.findViewById()获取对应的控件进行处理;

TextView leftView = (TextView) navigationBar.findViewById(R.id.tv_left);
leftView.setText("首页返回");

源码

你可能感兴趣的:(设计模式,NavigationBar,Builder设计模式)