Android View 高级框架一 Builder模式打造通用TitleBar

1 简介

我们在开发中往往都有一个TitleBar在APP最上面。例如下图
这里写图片描述这里写图片描述
这个TitleBar如果每次都写在布局中,则每个Activity都要在布局中展现。会增加布局的复杂度,另外也不便于维护。另外,对于不同的界面,有时候这个TitleBar又会有所差别。因此怎么定制化一个可以复用又方便维护的TitleBar呢?

当然,我们也可以单独写一个布局文件,然后每个Activity的界面include进去,但是这样每个Activity界面都需要要单独的findViewById。后期的维护性其实也不是很强。

2 TitleBar框架

设计的TitleBar框架如下图
这里写图片描述
可以看到,我们采用了Builder设计模式,来构造我们的TitleBar的各种参数。另外,我们在基类中指定了布局的文件及bindView的方法。从而使我们的应用能绑定到Activity的根布局上。
具体的逻辑如下:

    /**
     * 绑定View到ActivityRoot上
     */
    private void bindViewToActivityRoot() {
        ViewGroup activityRoot = null;
        //创建View
        if (mParams.mActivityRoot == null || activityRoot == null){
            //获取Activity的根布局
            activityRoot = (ViewGroup) ((Activity)mParams.mContext).findViewById(android.R.id.content);
            //获取我们在Activity中设置ContentView的View
            mParams.mActivityRoot = (ViewGroup)activityRoot.getChildAt(0);
            LogManager.i(TAG,"activityRoot size : " +activityRoot.getChildCount() + " mParams.mActivityRoot:" + mParams.mActivityRoot);
        }
        if (mParams.mActivityRoot == null){
            return;
        }

        mNavigationView = LayoutInflater.from(mParams.mContext)
                .inflate(bindLayoutId(),activityRoot,false);

        if (mParams.mActivityRoot instanceof RelativeLayout){
            //相对布局
            //先构造一个线性布局,指定垂直排列
            LinearLayout newActivityRoot = new LinearLayout(mParams.mContext);
            newActivityRoot.setOrientation(LinearLayout.VERTICAL);

            //移除原有的activityRoot的parent,否则会报"The specified child already has a parent. " +
            //"You must call removeView() on the child's parent first. 异常
            ViewGroup viewParent = (ViewGroup)mParams.mActivityRoot.getParent();
            viewParent.removeAllViews();

            //将titleBar添加为第一个child,原来的activityRoot为第二个
            newActivityRoot.addView(mNavigationView,0);
            newActivityRoot.addView(mParams.mActivityRoot,1);
            //将新的activityRoot添加到android.R.id.content中
            activityRoot.addView(newActivityRoot,0);

            LogManager.i(TAG,"mParams.mActivityRoot,child at 0 view:");

        }else {
            //添加View到mParams.mParent中
            mParams.mActivityRoot.addView(mNavigationView,0);
        }
        LogManager.i(TAG,"mParams.mActivityRoot,child:" + mParams.mActivityRoot.getChildCount());
        //绑定View
        bindView();
    }

这里有一点技巧就是,我们的Activity的布局最终是添加到id为android.R.id.content的一个FrameLayout
布局中的,然后获取我们的Activity界面的根布局,将TitleBar布局添加到根布局的第一个位置处。这样就完成了我们TitleBar布局的添加,省去了在xml中添加了。

一个具体的TitleBar需要继承BaseTitleBar和继承BaseTitleParams,然后实现bindLayoutId()和bindView()。

3 CommonTitleBar

CommonTitleBar是一个具体的例子,效果图如下:
这里写图片描述
我们先来看它的UML类图
这里写图片描述
可以看到,CommonTitleBar主要继承自BaseTitleBar。它的源码如下:

/**
 * Email: 1273482124@qq.com
 * Created by qiyei2015 on 2017/5/14.
 * Version: 1.0
 * Description:
 */
public class CommonTitleBar extends BaseTitleBar<CommonTitleParams> {

    protected CommonTitleBar(CommonTitleParams params) {
        super(params);
    }

    /**
     * 布局文件
     * @return
     */
    @Override
    public int bindLayoutId() {
        return R.layout.title_bar;
    }

    @Override
    public void bindView() {
        setText(R.id.title,mParams.mTitle);
        setText(R.id.right_text,mParams.mRightText);

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

    /**
     * 设置Tiltle
     * @param title
     */
    public void setTitle(String title){
        mParams.mTitle = title;
        setText(R.id.title,mParams.mTitle);
    }

    /**
     * 设置右侧文字
     * @param text
     * @return
     */
    public void setRightText(String text){
        mParams.mRightText = text;
        setText(R.id.right_text,mParams.mRightText);
    }

    /**
     * Builder模式设置各种效果
     */
    public static class Builder extends BaseTitleBar.Builder{
        /**
         * 所有的效果参数
         */
        CommonTitleParams mBarParams;

        public Builder(Context context) {
            super(context);
            mBarParams = new CommonTitleParams(context,null);
        }

        /**
         * 设置Title
         * @param title
         * @return
         */
        public Builder setTitle(String title){
            mBarParams.mTitle = title;
            return this;
        }

        /**
         * 设置右侧文字
         * @param text
         * @return
         */
        public Builder setRightText(String text){
            mBarParams.mRightText = text;
            return this;
        }

        /**
         * 设置右侧点击事件
         * @param listener
         * @return
         */
        public Builder setRightClickListener(View.OnClickListener listener){
            mBarParams.mRightClickListener = listener;
            return this;
        }

        /**
         * 创建CommonNavigationBar
         * @return
         */
        @Override
        public CommonTitleBar build() {
            return new CommonTitleBar(mBarParams);
        }
    }
}

CommonTitleBar主要封装了一些公共的返回按钮图标及响应的点击事件,右侧的文字,标题等内容。可根据项目的实际情况进行自定义其他的TitleBar
可以看到这是一个典型的Builder模式,主要的参数都存放在CommonTitleParams这个类中。如果项目有多个类型风格不同的TitleBar,则可以定义不同的TitleBar

详细的源码请参考
github https://github.com/qiyei2015/EssayJoke 中SDK 下的titlebar目录

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值