Builder设计模式构建NavigationBar

1. 概述


前边我们通过两节课来对Builder设计模式应该都有了一个了解和认识,如果对Builder设计模式还不是特别了解的,可以先去看下我前边的两篇文章
Builder设计模式构建自定义万能的Dialog
从源码角度分析AlertDialog,
那么这节课我们的内容还是对Builder设计模式的一个学习,我们学习下通过Builder设计模式如何去构建NavigationBar,来实现我们的导航栏。

2. 导航栏的几种写法


我们在项目中的导航栏一般都会有以下几种写法:
1>:直接在布局文件中写一个 layout_title,然后通过include直接引入到每个布局文件中;
2>:用系统的 ToolBar;
3>:自定义View;
当然除过以上的几种写法,肯定也会有其他的写法,在这里就不一一列举了,那么我们下边就针对于 使用 Builder设计模式构建NavigationBar方式来分析下
一般像顶部导航栏最好添加一些MetrialDesign的一些动画效果会比较好看一些。

3. 代码如下

头部的基类AbsNavigationBar代码如下:

/**
 * Email: [email protected]
 * Created by JackChen 2018/4/5 18:43
 * Version 1.0
 * Params:
 * Description:   头部的基类
 *                可能在整个项目中像这样的布局用的地方不是很多,但是必须要有,
 *                所以这里为了考虑头部可能出现的所有情况,也把基本的布局考虑进去
*/

public abstract class AbsNavigationBar

implements INavigationBar { private P mParams; private View mNavigationView; public AbsNavigationBar(P params) { this.mParams = params; createAndBindView(); } public P getParams() { return mParams; } /** * 设置文本 * @param viewId * @param text */ protected void setText(int viewId, String text) { TextView tv = findViewById(viewId); if(!TextUtils.isEmpty(text)){ tv.setVisibility(View.VISIBLE); tv.setText(text); } } /** * 设置点击 * @param viewId * @param listener */ protected void setOnClickListener(int viewId,View.OnClickListener listener){ findViewById(viewId).setOnClickListener(listener); } public T findViewById(int viewId){ return (T)mNavigationView.findViewById(viewId); } /** * 绑定和创建View */ private void createAndBindView() { // 1. 创建View if(mParams.mParent == null){ // 获取activity的根布局,View源码 // 方法1:android.R.id.content就是 android.R.layout.screen_simple中的一个 FrameLayout的一个id // ViewGroup activityRoot = (ViewGroup) ((Activity)(mParams.mContext)) // .findViewById(android.R.id.content); // 方法2:.getWindow().getDecorView() 表示直接加载的就是 android.R.layout.screen_simple的根布局,而根布局就是一个 LinearLayout // 所以不管 activity_main中的根布局是RelativeLayout、LinearLayout都可以 ViewGroup activityRoot = (ViewGroup) ((Activity)(mParams.mContext)) .getWindow().getDecorView() ; mParams.mParent = (ViewGroup) activityRoot.getChildAt(0); Log.e("TAG",mParams.mParent+""); } // 处理Activity的源码,后面再去看 if(mParams.mParent == null){ return; } mNavigationView = LayoutInflater.from(mParams.mContext). inflate(bindLayoutId(), mParams.mParent, false);// 插件换肤 // 2.添加 mParams.mParent.addView(mNavigationView, 0); applyView(); } // Builder 仿照系统写的, 套路,活 AbsNavigationBar Builder 参数Params public abstract static class Builder { public Builder(Context context, ViewGroup parent) { } public abstract AbsNavigationBar builder(); public static class AbsNavigationParams { public Context mContext; public ViewGroup mParent; public AbsNavigationParams(Context context, ViewGroup parent) { this.mContext = context; this.mParent = parent; } } } }

使用默认的头部的 DefaultNavigationBar代码如下:

public class DefaultNavigationBar extends
        AbsNavigationBar {

    public DefaultNavigationBar(DefaultNavigationBar.Builder.DefaultNavigationParams params) {
        super(params);
    }


    @Override
    public int bindLayoutId() {
        return R.layout.title_bar;
    }

    @Override
    public void applyView() {
        // 绑定效果
        setText(R.id.title, getParams().mTitle);
        setText(R.id.right_text, getParams().mRightText);

        setOnClickListener(R.id.right_text, getParams().mRightClickListener);
        // 左边 要写一个默认的  finishActivity
        setOnClickListener(R.id.back,getParams().mLeftClickListener);
    }


    public static class Builder extends AbsNavigationBar.Builder {

        DefaultNavigationParams P;


        public Builder(Context context, ViewGroup parent) {
            super(context, parent);
            P = new DefaultNavigationParams(context, parent);
        }

        public Builder(Context context) {
            super(context, null);
            P = new DefaultNavigationParams(context, null);
        }

        @Override
        public DefaultNavigationBar builder() {
            DefaultNavigationBar navigationBar = new DefaultNavigationBar(P);
            return navigationBar;
        }

        // 1. 设置所有效果

        public DefaultNavigationBar.Builder setTitle(String title) {
            P.mTitle = title;
            return this;
        }


        public DefaultNavigationBar.Builder setRightText(String rightText) {
            P.mRightText = rightText;
            return this;
        }

        /**
         * 设置右边的点击事件
         */
        public DefaultNavigationBar.Builder
        setRightClickListener(View.OnClickListener rightListener) {
            P.mRightClickListener = rightListener;
            return this;
        }

        /**
         * 设置左边的点击事件
         */
        public DefaultNavigationBar.Builder
        setLeftClickListener(View.OnClickListener rightListener) {
            P.mLeftClickListener = rightListener;
            return this;
        }

        /**
         * 设置右边的图片
         */
        public DefaultNavigationBar.Builder setRightIcon(int rightRes) {

            return this;
        }

        public static class DefaultNavigationParams extends
                AbsNavigationBar.Builder.AbsNavigationParams {


            // 2.所有效果放置
            public String mTitle;

            public String mRightText;

            // 后面还有一些通用的
            public View.OnClickListener mRightClickListener;

            public View.OnClickListener mLeftClickListener = new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // 关闭当前Activity
                    ((Activity) mContext).finish();
                }
            };

            public DefaultNavigationParams(Context context, ViewGroup parent) {
                super(context, parent);
            }
        }
    }
}

在MainActivity中的 initTitle()中直接 一句代码引用即可:

public class MainActivity extends BaseSkinActivity {


    @Override
    protected void setContentView() {
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void initData() {

    }

    @Override
    protected void initView() {

    }

    @Override
    protected void initTitle() {
        DefaultNavigationBar navigationBar = new
                DefaultNavigationBar.Builder(this)
                .setTitle("投稿")
                .builder();
    }
}

注意:

在AbsNavigationBar中的这两种方法要注意,这两种方法代表的意思是一样的

// 方法1:android.R.id.content就是 android.R.layout.screen_simple中的一个 FrameLayout的一个id
// ViewGroup activityRoot = (ViewGroup) ((Activity)(mParams.mContext))
// .findViewById(android.R.id.content);

// 方法2:.getWindow().getDecorView() 表示直接加载的就是 android.R.layout.screen_simple的根布局,而根布局就是一个 LinearLayout
// 所以不管 activity_main中的根布局是RelativeLayout、LinearLayout都可以
 ViewGroup activityRoot = (ViewGroup) ((Activity)(mParams.mContext))
        .getWindow().getDecorView() ;

 mParams.mParent = (ViewGroup) activityRoot.getChildAt(0);
            Log.e("TAG",mParams.mParent+"");

分析方法1:

方法1中的findViewById(android.R.id.content);是直接加载的是 系统的资源文件,即就是android.R.layout.screen_simple中的一个叫做 android.R.id.content的布局,它是一个FrameLayout,也就是说我们是把我们的 setContentView的布局其实是加载到 这个资源文件中的 android.R.id.content中的,它是一个 mContentParent,是一个 FrameLayout,也就是说我们是把 setContentView的布局是加载到 mContentParent中的,android.R.layout.screen_simple的布局文件如下:


    
    

分析方法2:

方法2其实就是 加载的是DecorView,而DecorView中加载的就是 系统的资源文件,就是 android.R.layout.screen_simple,其实就是直接加载该布局文件的根布局 LinearLayout,这样的话,不管 我们自己的 setContentView()中根布局是 LinearLayout还是RelativeLayout,都可以直接把布局加载到第0个位置

上边的两种方法其实考的就是 setContentView()的加载流程,如果不是很懂的,可以去看下我前边的文章,setContentView的加载流程分析

代码已上传至github:
https://github.com/shuai999/EssayJoke_day_08.git

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