美文网首页
BaseActivity自定义多样化标题布局

BaseActivity自定义多样化标题布局

作者: 烤地瓜次不次 | 来源:发表于2018-04-05 13:07 被阅读0次

    标题栏这种东西,每个App都会有,但是不是每个设计师都会为一个App设计Android和IOS两种风格,所以苦了Android开发的。不能用系统的,所以我们来自定义好了。(该篇文章主要提供布局文件在Acitivity使用时,标题和内容的解耦方案)

    需求分析

    1. 标题栏出现的位置可选
    2. 标题栏与内容相互之间的位置可选
    3. 标题栏支持Toolbar调用

    要优雅

    1. 基类实现方式,继承配置即可使用
    2. 不影响Super Activity的正常使用
    3. 良好的容错率
    4. 可配置标题栏位置及使用方式
    5. 支持自定义rootView及TitleStyle

    OK,我们来写代码

    导入依赖库

        // 这里注意,如果只有一个app的module,可以使用implementation
        implementation 'com.android.support:appcompat-v7:26.1.0'
        // 如果BaseActivity的代码作为lib库,使用api
        api 'com.android.support:appcompat-v7:26.1.0'
    

    创建TitleActivity类

        /**
         * 自定义标题的BaseActivity
         * 使用时需配置style Theme.AppCompat.NoActionBar
         * setTitleView 设置标题
         * setContentView 设置内容
         * 复写titleStyle 设置标题风格
         */
        public class TitleActivity extends AppCompatActivity {
            // 获取自身实力的引用,防止代码里出现类似BaseActivity.this这种调用方式(个人习惯,查找类在哪里被引用的时候不乱)
            protected TitleActivity thisActivity;
            private LayoutInflater inflater;
        }
    

    预定义TitleStyle

        protected static final int TITLE_NONE = 0;// 无标题
        protected static final int TITLE_ABOVE_CONTENT = 1;// 内容在标题下方
        protected static final int TITLE_BELOW_CONTENT = 2;// 标题在底部,内容在上方
        protected static final int TITLE_FLOAT_TOP = 3;// 内容铺满全局,标题悬浮在内容上方
        protected static final int TITLE_FLOAT_BOTTOM = 3;// 内容铺满全局,标题悬浮在内容下方
        protected static final int TITLE_CONTENT_SCROLL = 4;// 标题随内容滚动
        /**
         * 标题栏风格
         */
        protected int titleStyle() {
            return TITLE_ABOVE_CONTENT;
        }
    

    添加标题的设置方法

        protected void setTitleView(int layoutResID) {
            if (titleStyle() == TITLE_NONE) {
                titleView = inflater.inflate(layoutResID, null);
            } else {
                titleView = inflater.inflate(layoutResID, rootView, false);
                notifyTitle();
            }
        }
        
        private void notifyTitle() {
            switch (titleStyle()) {
                case TITLE_ABOVE_CONTENT:
                default:
                    rootView.removeAllViews();
                    rootView.addView(titleView);
                    if (contentView != null) {
                        rootView.addView(contentView);
                    }
            }
        }
    

    复写setContentView

        @Override
        public void setContentView(int layoutResID) {
            if (titleStyle() == TITLE_NONE) {
                super.setContentView(layoutResID);
            } else {
                contentView = inflater.inflate(layoutResID, rootView, false);
                notifyContent(contentView.getLayoutParams());
            }
        }
    
        @Override
        public void setContentView(View view) {
            if (titleStyle() == TITLE_NONE) {
                super.setContentView(view);
            } else {
                contentView = view;
                notifyContent(view.getLayoutParams());
            }
        }
    
        @Override
        public void setContentView(View view, ViewGroup.LayoutParams params) {
            if (titleStyle() == TITLE_NONE) {
                super.setContentView(view, params);
            } else {
                contentView = view;
                notifyContent(params);
            }
        }
        
        private void notifyContent(ViewGroup.LayoutParams params) {
            switch (titleStyle()) {
                case TITLE_ABOVE_CONTENT:
                default:
                    // content置空
                    int childCount = rootView.getChildCount();
                    if (childCount > 2) {
                        rootView.removeViewAt(childCount - 1);
                    }
                    if (contentView != null) {// 添加新的content
                        rootView.addView(contentView, params);
                    }
            }
        }
    

    在onCreate中初始化rootView

        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            thisActivity = this;
            inflater = LayoutInflater.from(thisActivity);
            if (titleStyle() != TITLE_NONE) {
                buildRootViewByStyle();
            }
        }
    
        // 初始化rootView
        private void buildRootViewByStyle() {
            switch (titleStyle()) {
                case TITLE_ABOVE_CONTENT:
                default:
                    LinearLayout ll = new LinearLayout(thisActivity);
                    ll.setOrientation(LinearLayout.VERTICAL);
                    rootView = ll;
            }
            super.setContentView(rootView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        }
    

    是否开启lib id

        <!-- 在values中创建ids.xml文件 -->
        <item name="TitleActivity_id_Toolbar" type="id"/>
        <item name="TitleActivity_id_back" type="id"/>
        <item name="TitleActivity_id_title" type="id"/>
    
        /**
         * @return true 自动检索相关ids并做响应操作 false 不做固定id检索
         */
        protected boolean libTitleIdsEnable() {
            return false;
        }
    
        /* 在标题初始化后 */
        // init toolbar
        if (libTitleIdsEnable()) {
                try {
                    tv_title = findViewById(R.id.TitleActivity_id_title);
                    setCustomTitle();
                } catch (ClassCastException e) {
                    throw new RuntimeException("title must instanceof TextView");
                }
                btn_back = findViewById(R.id.TitleActivity_id_back);
                if (btn_back != null) {
                    if (backListener != null) {
                        btn_back.setOnClickListener(backListener);
                    } else {
                        btn_back.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                onBackPressed();
                            }
                        });
                    }
                }
            }
    

    对外提供修改方法

        protected Toolbar getToolbar() {
            return toolbar;
        }
    
        private CharSequence titleCharSequence;
        private int titleResId = -1;
    
        protected void setCustomTitle(CharSequence title) {
            this.titleCharSequence = title;
            this.titleResId = -1;
            setCustomTitle();
        }
    
        protected void setCustomTitle(int title) {
            this.titleResId = title;
            this.titleCharSequence = null;
            setCustomTitle();
        }
    
        private void setCustomTitle() {
            if (tv_title != null) {
                if (titleCharSequence != null) {
                    tv_title.setText(titleCharSequence);
                } else if (titleResId != -1) {
                    tv_title.setText(titleResId);
                }
            }
        }
    
        private View.OnClickListener backListener;
    
        protected void setOnBackClickListener(View.OnClickListener listener) {
            backListener = listener;
            if (btn_back != null) {
                btn_back.setOnClickListener(listener);
            }
        }
    

    使用方法

        <! -- 在布局文件声明lib 中的id -->
        android:id="@id/TitleActivity_id_title"
    
    public class TestTitleActivity extends TitleActivity {
    
        @Override
        protected boolean libTitleIdsEnable() {
            return true;
        }
        
        @Override
        protected int titleStyle() {
            return TITLE_ABOVE_CONTENT;
        }
    
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setTitleView(R.layout.layout_title);
            setContentView(R.layout.activity_title_test);
             // TODO: do other
             setCustomTitle("HaHaHa");// 设置title
        }
    }
    

    让TitleStyle优雅起来

    为TitleStyle添加抽象工厂模式

    创建接口

    public interface ITitleStyle {
    
        boolean hasTitle();// 是否包括标题
        boolean bindSystemActionBar();// Toolbar是否绑定系统ActionBar
        ViewGroup onBuildRootViewByStyle(Context context);// 创建rootView
        void onTitleLayoutSet(ViewGroup rootView, View titleView, View contentView);// 放置标题布局
        void onContentLayoutSet(ViewGroup rootView, View titleView, View contentView, ViewGroup.LayoutParams params);// 放置内容布局位置
        
    }
    

    创建默认Style并实现接口

    /**
     * 线性布局
     * 内容在标题下方
     * 这里的逻辑是从BaseAcitivity中抽离的
     */
    public class DefaultTitleStyle implements ITitleStyle {
    
        @Override
        public boolean hasTitle() {
            return true;
        }
    
        @Override
        public boolean bindSystemActionBar() {
            return true;
        }
    
        @Override
        public void onTitleLayoutSet(ViewGroup rootView, View titleView, View contentView) {
            rootView.removeAllViews();
            rootView.addView(titleView);
            if (contentView != null) {
                rootView.addView(contentView);
            }
        }
    
        @Override
        public void onContentLayoutSet(ViewGroup rootView, View titleView, View contentView, ViewGroup.LayoutParams params) {
    // content置空
            int childCount = rootView.getChildCount();
            if (childCount > 2) {
                rootView.removeViewAt(childCount - 1);
            }
            if (contentView != null) {// 添加新的content
                rootView.addView(contentView, params);
            }
        }
    
        @Override
        public ViewGroup onBuildRootViewByStyle(Context context) {
            LinearLayout ll = new LinearLayout(context);
            ll.setOrientation(LinearLayout.VERTICAL);
            return ll;
        }
    
    }
    

    于是,BaseAcitivity中的实现变为

    /**
     * 自定义标题的BaseActivity
     * 使用时需配置style Theme.AppCompat.NoActionBar
     * setTitleView 设置标题
     * setContentView 设置内容
     * 复写titleStyle 设置标题风格
     */
    public class TitleActivity extends AppCompatActivity {
        ……
        private ViewGroup rootView;
        private View titleView;
        private Toolbar toolbar;
        private View contentView;
        ……
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ……
            titleStyle = titleStyle();
            if (titleStyle.hasTitle()) {
                rootView = titleStyle.onBuildRootViewByStyle(thisActivity);
                super.setContentView(rootView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            }
        }
    
        protected void setTitleView(int layoutResID) {
            if (!titleStyle.hasTitle()) {
                titleView = inflater.inflate(layoutResID, null);
            } else {
                titleView = inflater.inflate(layoutResID, rootView, false);
                titleStyle.onTitleLayoutSet(rootView, titleView, contentView);
            }
            // init toolbar
            if (titleView instanceof Toolbar) {
                toolbar = (Toolbar) titleView;
                if (titleStyle.bindSystemActionBar()) {
                    setSupportActionBar(toolbar);
                }
            } else if (libTitleIdsEnable()) {
                toolbar = findViewById(R.id.TitleActivity_id_Toolbar);
                if (titleStyle.bindSystemActionBar()) {
                    setSupportActionBar(toolbar);
                }
            }
            // init title and back button
            ……
        }
    
        @Override
        public void setContentView(int layoutResID) {
            if (!titleStyle.hasTitle()) {
                super.setContentView(layoutResID);
            } else {
                contentView = inflater.inflate(layoutResID, rootView, false);
                titleStyle.onContentLayoutSet(rootView, titleView, contentView, contentView.getLayoutParams());
            }
        }
        
        ……
    
        /**
         * 标题风格
         */
        protected ITitleStyle titleStyle() {
            return new DefaultTitleStyle();
        }
        
        ……
    
    }
    
    

    与Activity解耦

    那么,当使用时,如果遇到以存在BaseAcitivity,无法继承怎么办?哼,一点也不优雅

    封装LayoutHandler

    public class LayoutHandler {
    
        protected AppCompatActivity thisActivity;
        private LayoutInflater inflater;
    
        private ITitleStyle titleStyle;
    //    protected static final int TITLE_BELOW_CONTENT = 2;// 标题在底部,内容在上方
    //    protected static final int TITLE_FLOAT_TOP = 3;// 内容铺满全局,标题悬浮在内容上方
    //    protected static final int TITLE_FLOAT_BOTTOM = 3;// 内容铺满全局,标题悬浮在内容下方
    //    protected static final int TITLE_CONTENT_SCROLL = 4;// 标题随内容滚动
        private boolean libTitleIdsEnable;
    
        private ViewGroup rootView;
        private View titleView;
        private Toolbar toolbar;
        private View contentView;
        private TextView tv_title;
        private View.OnClickListener backListener;
    
        private CharSequence titleCharSequence;
        private int titleResId = -1;
        
        private View btn_back;
    
    
        private LayoutHandler() {
        }
    
        public boolean onCreate() {
            if (titleStyle.hasTitle()) {
                rootView = titleStyle.onBuildRootViewByStyle(thisActivity);
                return true;
            }
            return false;
        }
    
        public ViewGroup getRootView() {
            return rootView;
        }
    
        protected Toolbar getToolbar() {
            return toolbar;
        }
    
        public void setTitleView(int layoutResID) {
            if (!titleStyle.hasTitle()) {
                titleView = inflater.inflate(layoutResID, null);
            } else {
                titleView = inflater.inflate(layoutResID, rootView, false);
                titleStyle.onTitleLayoutSet(rootView, titleView, contentView);
            }
            // init toolbar
            if (titleView instanceof Toolbar) {
                toolbar = (Toolbar) titleView;
                if (titleStyle.bindSystemActionBar()) {
                    thisActivity.setSupportActionBar(toolbar);
                }
            } else if (libTitleIdsEnable) {
                toolbar = thisActivity.findViewById(R.id.TitleActivity_id_Toolbar);
                if (titleStyle.bindSystemActionBar()) {
                    thisActivity.setSupportActionBar(toolbar);
                }
            }
            // init title and back button
            if (libTitleIdsEnable) {
                try {
                    tv_title = thisActivity.findViewById(R.id.TitleActivity_id_title);
                    setCustomTitle();
                } catch (ClassCastException e) {
                    throw new RuntimeException("title must instanceof TextView");
                }
                btn_back = thisActivity.findViewById(R.id.TitleActivity_id_back);
                if (btn_back != null) {
                    if (backListener != null) {
                        btn_back.setOnClickListener(backListener);
                    } else {
                        btn_back.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                thisActivity.onBackPressed();
                            }
                        });
                    }
                }
            }
        }
    
        public boolean setContentView(View view, ViewGroup.LayoutParams params) {
            if (titleStyle.hasTitle()) {
                contentView = view;
                titleStyle.onContentLayoutSet(rootView, titleView, contentView, params);
                return true;
            }
            return false;
        }
    
        public boolean setContentView(View view) {
            if (titleStyle.hasTitle()) {
                contentView = view;
                titleStyle.onContentLayoutSet(rootView, titleView, contentView, contentView.getLayoutParams());
                return true;
            }
            return false;
        }
    
        public boolean setContentView(int layoutResID) {
            if (titleStyle.hasTitle()) {
                contentView = inflater.inflate(layoutResID, rootView, false);
                titleStyle.onContentLayoutSet(rootView, titleView, contentView, contentView.getLayoutParams());
                return true;
            }
            return false;
        }
    
        protected void setCustomTitle(CharSequence title) {
            this.titleCharSequence = title;
            this.titleResId = -1;
            setCustomTitle();
        }
    
        protected void setCustomTitle(int title) {
            this.titleResId = title;
            this.titleCharSequence = null;
            setCustomTitle();
        }
    
        private void setCustomTitle() {
            if (tv_title != null) {
                if (titleCharSequence != null) {
                    tv_title.setText(titleCharSequence);
                } else if (titleResId != -1) {
                    tv_title.setText(titleResId);
                }
            }
        }
        
        public void setOnBackClickListener(View.OnClickListener listener) {
            this.backListener = listener;
            if (btn_back != null) {
                btn_back.setOnClickListener(listener);
            }
        }
    
    }
    
    

    为LayoutHandler添加建造者模式

        public static class Builder {
    
            LayoutHandler handler;
    
            public Builder() {
                handler = new LayoutHandler();
            }
    
            public Builder setActivity(AppCompatActivity act) {
                handler.thisActivity = act;
                handler.inflater = LayoutInflater.from(act);
                return this;
            }
    
            public Builder setTitleStyle(ITitleStyle titleStyle) {
                handler.titleStyle = titleStyle;
                return this;
            }
    
            public Builder setLibTitleIdsEnable(boolean libTitleIdsEnable) {
                handler.libTitleIdsEnable  = libTitleIdsEnable;
                return this;
            }
    
            public LayoutHandler build() {
                return handler;
            }
    
        }
    

    于是BaseActivity简化为

    /**
     * 自定义标题的BaseActivity
     * 使用时需配置style Theme.AppCompat.NoActionBar
     * setTitleView 设置标题
     * setContentView 设置内容
     * 复写titleStyle 设置标题风格
     */
    public class TitleActivity extends AppCompatActivity {
        // 获取自身实力的引用,防止代码里出现类似BaseActivity.this这种调用方式(个人习惯,查找类在哪里被引用的时候不乱)
        protected TitleActivity thisActivity;
        private LayoutHandler layoutHandler;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            thisActivity = this;
            layoutHandler = new LayoutHandler.Builder()
                    .setActivity(thisActivity)
                    .setTitleStyle(titleStyle())
                    .setLibTitleIdsEnable(libTitleIdsEnable())
                    .build();
            if (layoutHandler.onCreate()) {
                super.setContentView(layoutHandler.getRootView(), new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            }
        }
    
        @Override
        public void setContentView(int layoutResID) {
            if (!layoutHandler.setContentView(layoutResID)) {
                super.setContentView(layoutResID);
            }
        }
    
        @Override
        public void setContentView(View view) {
            if (!layoutHandler.setContentView(view)) {
                super.setContentView(view);
            }
        }
    
        @Override
        public void setContentView(View view, ViewGroup.LayoutParams params) {
            if (!layoutHandler.setContentView(view, params)) {
                super.setContentView(view, params);
            }
        }
    
        /**
         * 标题风格
         */
        protected ITitleStyle titleStyle() {
            return new DefaultTitleStyle();
        }
    
        /**
         * @return true 自动检索相关ids并做响应操作 false 不做固定id检索
         */
        protected boolean libTitleIdsEnable() {
            return false;
        }
        /**
         * 设置标题布局
         */
        protected void setTitleView(int layoutResID) {
            layoutHandler.setTitleView(layoutResID);
        }
    
        protected Toolbar getToolbar() {
            return layoutHandler.getToolbar();
        }
    
        /**
         * 设置标题
         */
        protected void setCustomTitle(CharSequence title) {
            layoutHandler.setCustomTitle(title);
        }
        /**
         * 设置标题
         */
        protected void setCustomTitle(int title) {
            layoutHandler.setCustomTitle(title);
        }
    
        /**
         * id为TitleActivity_id_back的view被点击的回调
         */
        protected void setOnBackClickListener(View.OnClickListener listener) {
            layoutHandler.setOnBackClickListener(listener);
        }
        
    }
    

    相关文章

      网友评论

          本文标题:BaseActivity自定义多样化标题布局

          本文链接:https://www.haomeiwen.com/subject/sznrhftx.html