博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MVP实战心得(五) Toolbar封装优化,放弃butterknife
阅读量:5886 次
发布时间:2019-06-19

本文共 13190 字,大约阅读时间需要 43 分钟。

转载请标明出处: 本文出自:

#前言:

继 做了很多修改.期间有很多纠结的地方, 对比google对Activity以及AppcompatActivity的思路, 将原来的代码区分开,弄成2个module. 一个对应FragmentActivity 一个对应AppcompatActivity 区分开来,不再写在一起.

如不依赖appcompat-v7包就不能使用appcompat控件一样<__>

#1.Toolbar的封装处理 #####试想了很多场景.死了n个脑细胞,最后得出来的结构图:

##(1).Appcompat风格:

复制代码

###Toolbar模版

复制代码

设计思路: 1.最外层使用CoordinatorLayout,提供动画,联动特性. 2.使用AppBarLayout,可以添加Toolbar等多个控件,可以使用Tablayout,CollapsingToolbarLayout,Toolbar等. 提供扩展的可能性 3.主要内容使用FrameLayout,可以扩展封装loadingView等.

##(2).非Appcompat风格:

复制代码

###Toolbar模版

复制代码

设计思路: 1.Toolbar必须使用Appcompat包,如果使用的普通的Acitivity就会出问题. 所以需要提供2套module 2.使用LinearLayout添加Toolbar,这里的Toolbar其实是一个RelativeLayout. 3.主要内容使用FrameLayout,可以扩展封装loadingView等.

##(3).ToolbarHelper: 只贴部分代码

public abstract class ToolbarHelper {  /**     * 设置滑动Flag     * @param viewId     * @param flag     * @return     */    public abstract boolean setScrollFlag(@IdRes int viewId, @AppBarLayout.LayoutParams.ScrollFlags int flag);    /**     * 获取AppBarLayout中的View     * @param viewId     * @param 
* @return */ public abstract
V findAppBarView(@IdRes int viewId); /** * 获取AppBarLayout * @return */ public abstract View getAppBarLayout(); /** * 获取Toolbar * @return */ public abstract Toolbar getToolbar();}复制代码

###具体实现:

/** * @author jlanglang  2017/2/22 16:58 * @版本 2.0 * @Change */abstract class BaseToolBarHelperImpl extends ToolbarHelper {    //ToolbarLayout的资源id    int mToolbarLayout;    Toolbar mToolbar;    //通过UIView接口调用.    UIView mUIView;    //最外层View    View mRootView;    AppBarLayout mAppBarLayout;    private boolean isMaterialDesign;    //模仿ViewHolder机制.保存View.避免多次去findviewbyid同一个view    private SparseArray
mViews; public BaseToolBarHelperImpl(@NonNull UIView uiView, View rootView, int toolbarLayout) { mUIView = uiView; mRootView = rootView; mToolbarLayout = toolbarLayout; mViews = new SparseArray<>(); //初始化AppBarLayout mAppBarLayout = (AppBarLayout) mRootView.findViewById(R.id.app_bar); mAppBarLayout.removeAllViews(); //将toolbarLayout添加到AppBarLayout中 View inflate = LayoutInflater.from(mUIView.getContext()).inflate(mToolbarLayout, mAppBarLayout, true); mToolbar = (Toolbar) inflate.findViewById(R.id.tl_costom); if (mToolbar != null) { //传入的toolbarLayout中包含Toolbar,才设置. mUIView.setSupportActionBar(mToolbar); } //交给子类去初始化Toolbar initToolbar(); } /* *初始化Toolbar */ public abstract void initToolbar(); /** * 从AppBarLayout中获取控件 * * @param viewId * @param
* @return */ @Nullable @Override public
V findAppBarView(@IdRes int viewId) { View view = mViews.get(viewId); if (view == null && mAppBarLayout != null) { view = mAppBarLayout.findViewById(viewId); mViews.put(viewId, view); } return (V) view; } /** * 设置控件滑动效果 * * @param viewId 控件的资源id * @param flag 滑动flag * @return 是否设置成功 */ @Override public boolean setScrollFlag(@IdRes int viewId, @AppBarLayout.LayoutParams.ScrollFlags int flag) { View view = findAppBarView(viewId); if (view != null) { try { AppBarLayout.LayoutParams layoutParams = (AppBarLayout.LayoutParams) view.getLayoutParams(); layoutParams.setScrollFlags(flag); } catch (ClassCastException e) { e.printStackTrace(); return false; } catch (NullPointerException e) { e.printStackTrace(); return false; } } else { return false; } return true; } @Nullable @Override public Toolbar getToolbar() { return mToolbar; }复制代码

###BaseAcitivity部分代码:

package com.baozi.mvpdemo.base;/** * @author jlanglang  2016/1/5 9:42 */public abstract class BaseActivity
extends AppCompatActivity implements BaseActivityView { protected T mPresenter; private SparseArray
mViews; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mViews = new SparseArray<>(); //创建presenter mPresenter = initPresenter(); //绑定Activity mPresenter.onAttch(this); //创建ContentView View view = initView(LayoutInflater.from(this), savedInstanceState); super.setContentView(view); //初始化presenter mPresenter.onCreate(); //延时加载数据. Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() { @Override public boolean queueIdle() { mPresenter.loadData(); return false; } }); } @Override public void setContentView(@LayoutRes int layoutResID) { } @Override public void setContentView(View view) { } @Override public void setContentView(View view, ViewGroup.LayoutParams params) { } /** * 通过viewId获取控件 * * @param viewId 资源id * @return */ @Override public
V findView(@IdRes int viewId) { View view = mViews.get(viewId); if (view == null) { view = super.findViewById(viewId); mViews.put(viewId, view); } return (V) view; } @Override public View findViewById(@IdRes int id) { return findView(id); } /** * 初始化ContentView * 建议不要包含toolbar * * @param inflater * @param savedInstanceState * @return */ @NonNull protected abstract View initView(@NonNull LayoutInflater inflater, Bundle savedInstanceState); /** * 子类实现Presenter,且必须继承BasePrensenter * * @return */ protected abstract T initPresenter();}复制代码

###提供模版Activity:

/** * 设置了默认的布局,默认的几个Toolbar模版,实现了ToolbarView, */public abstract class TempletActivity
extends BaseActivity
implements ToolbarView { private ToolbarHelper mToolbarHelper; private View rootView; @NonNull @Override protected View initView(@NonNull LayoutInflater inflater, Bundle savedInstanceState) { ActionBar supportActionBar = getSupportActionBar(); if (supportActionBar != null) { throw new IllegalStateException("pleace exends BaseActivity,TempletActivity theme must Noactionbar"); } rootView = inflater.inflate(R.layout.activity_templet, null); //创建toolbar mToolbarHelper = getToolbarHelper(); //ContentView容器 FrameLayout contentGroup = (FrameLayout) rootView.findViewById(R.id.templet_content); //真正的创建contentView View contentView = initContentView(inflater, contentGroup, savedInstanceState); contentGroup.removeAllViews(); contentGroup.addView(contentView); //交给Persenter去扩展 mPresenter.wapperContentView(contentGroup); return rootView; } //继承的子类去实现 @NonNull protected abstract View initContentView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState); /** * 默认使用base_toolbar * 如果不需要toolbar,请复写,并返回0.或者-1 * * @return */ @Override public int initToolbarLayout() { return ToolbarHelper.TOOLBAR_TEMPLET_DEFUATL; } /** * 此方法用于初始化菜单,其中menu参数就是即将要显示的Menu实例。 返回true则显示该menu,false 则不显示; * (只会在第一次初始化菜单时调用) */ @Override public boolean onCreateOptionsMenu(Menu menu) { if (!isMaterialDesign() || getToolbarHelper() == null) { return false; } return super.onCreateOptionsMenu(menu); } /** * 在onCreateOptionsMenu执行后,菜单被显示前调用;如果菜单已经被创建,则在菜单显示前被调用。 同样的, * 返回true则显示该menu,false 则不显示; (可以通过此方法动态的改变菜单的状态,比如加载不同的菜单等) */ @Override public boolean onPrepareOptionsMenu(Menu menu) { return super.onPrepareOptionsMenu(menu); } /** * 显示menu的icon * * @param view * @param menu * @return */ @Override protected boolean onPrepareOptionsPanel(View view, Menu menu) { if (menu != null) { if (menu.getClass().getSimpleName().equals("MenuBuilder")) { try { Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE); m.setAccessible(true); m.invoke(menu, true); } catch (Exception e) { Log.e(getClass().getSimpleName(), "onMenuOpened...unable to set icons for overflow menu", e); } } } return super.onPrepareOptionsPanel(view, menu); } /** * 每次菜单被关闭时调用.(菜单被关闭有三种情形,menu按钮被再次点击、back按钮被点击或者用户选择了某一个菜单项) */ @Override public void onOptionsMenuClosed(Menu menu) { super.onOptionsMenuClosed(menu); } /** * 菜单项被点击时调用,也就是菜单项的监听方法。 * 通过这几个方法,可以得知,对于Activity,同一时间只能显示和监听一个Menu 对象. */ @Override public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); } @Override public TempletActivity getActivity() { return this; } /** * 切换MaterialDesign风格. * * @param isMaterialDesign */ @Override public void setMaterialDesignEnabled(boolean isMaterialDesign) { getToolbarHelper().setMaterialDesignEnabled(isMaterialDesign); } @Override public boolean isMaterialDesign() { return false; } /** * 如果设置的主题不是NoActionBar或者initToolbar()返回是0,则返回null. * * @return mToolbar 可能为null. */ public Toolbar getToolbar() { return getToolbarHelper().getToolbar(); } /** * @return */ @Override public ToolbarHelper getToolbarHelper() { if (mToolbarHelper == null) { mToolbarHelper = ToolbarHelper.Create(this, rootView, initToolbarLayout()); } return mToolbarHelper; } @Override protected abstract T initPresenter();}复制代码

###使用例子:

public class MainAcitivity extends TempletActivity
{ @NonNull @Override protected View initContentView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { getToolbarHelper().setTitle("首页"); getToolbarHelper().setRightText("213", null); return inflater.inflate(R.layout.activity_main, null); } //这里偷懒,就不去单独写个PresenterImpl了 @Override protected TempletPresenter initPresenter() { //需要继承 return new TempletPresenter
() { @Override public void onCreate() { //设置滑动效果 mView.getToolbarHelper().setScrollFlag(R.id.tl_costom, AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL| AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS); } @Override public void loadData() { } }; } //重写该方法,设置ToolbarLayout @Override public int initToolbarLayout() { return ToolbarHelper.TOOLBAR_TEMPLET_DEFUATL; }}复制代码

##(4).Appcompat风格的要点:

1.如果自定义页面,或者模版的样式不符合你的要求,可以直接继承BaseActivity,BaseFragment 实现initView(@NonNull LayoutInflater inflater, Bundle savedInstanceState);方法 该方法相当于setContentView(),onCreateView(); 或者接着往下看,有惊喜。。

2.由于BaseActivity,BaseFragment都继承UIVIew. 通过initView()方法来初始化View 所以两者之间切换,改动可以非常的小.

3.TempletActivity持有ToolbarHelper的实现类,并且实现了ToolbarView.UIView, Presenter可以通过继承了ToolbarView.UIViewView来操作TempletActivity.

4.BaseActivityBaseFragment,属于基类,无需关系Toolbar的情况.也就不需要ToolbarHelper

5.通过重写initToolbarLayout()就能设置不同样式的Toolbar,如果样式满足不了需求,可以直接继承BaseActivity,BaseFragment来自定义

6.可以通过ToolbarHelper获取mApplayout,进行增删子View.以及设置属性.

7.可以通过ToolbarHelperfindAppBarView(id)获取mApplayout中的子控件.

8.可以通过ToolbarHelpersetScrollFlag(id,flag)设置mApplayout中子控件的滑动效果. 9.可以自定义toolbarlayout,只不过Toolbar的id要求命名为tl_costom,否则无法获取的Toolbar当然,也可以随便起名字.不过就得手动做一些事了,通过findAppBarView(id)获取到Toolbar,然后setSupportActionBar() ##(5)默认的四种样式: 1.带TabLayout的Toolbar

2.啥也没有的Toolbar

3.自定义了一些VIew的ToolBar

4.可以通过滑动上推折叠的Toolbar

缺点:对AppbarLayout的一些设置只能通过代码来设定了。

#2.摆脱butterknife

在实践组件化的时候,发现butterknife不好用,moudle里面找不到view。 后来看git上的说明,把R改成R2.发现有点蛋疼,不是很好用了,干脆弃用算了吧。

最后重写了findviewbyId(),通过泛型,减少强转操作。不用每次都去强转了。不过得自己知道对应的控件id是什么类型了,这个不可能不知道吧。

部分代码:

public abstract class BaseActivity
extends AppCompatActivity implements BaseActivityView { private SparseArray
mViews; * 通过viewId获取控件 * * @param viewId 资源id * @return */ @Override public
V findView(@IdRes int viewId) { View view = mViews.get(viewId); if (view == null) { view = super.findViewById(viewId); mViews.put(viewId, view); } return (V) view; } @Override public View findViewById(@IdRes int id) { return findView(id); }复制代码

自己写findviewbyid吧。。用工具生成也可以的。

#3.普通风格 普通风格的具体实现代码就不贴了,这文已经很长了,哈哈.有兴趣直接github看代码好了.

#4.Fragment的Toolbar封装 具体实现和activity差不多,因为我一直以来的设想就是改很少的代码就能两者切换. 这里就不贴了(其实是我还没写.),陆续更新. 如果你看我这一系列文章,会发现,最开始的封装结构和现在的有很大的差别了.为什么不去更新改掉以前的 我觉得这是成长的记录吧.哈哈

#再附上githubdemo地址,时不时就更新


您的喜欢与回复是我最大的动力-_-

你可能感兴趣的文章
http响应Last-Modified和ETag
查看>>
MySQL索引类型一览 让MySQL高效运行起来
查看>>
Linux下启动停止查看杀死Tomcat进程
查看>>
bt分析之bt种子发布---做种(2)
查看>>
makefile(一)makefile文件组成
查看>>
我的友情链接
查看>>
Java异步线程池中处理logback MDC
查看>>
CentOS 6.3开机自动联网
查看>>
springMVC 拦截器 HandlerInterceptor 用法
查看>>
C# System.Data.OracleClient requires Oracle client software version 8.1.7 or greater
查看>>
X-UA-Compatible兼容模式
查看>>
设计模式之观察者模式
查看>>
lucene-JE中文分词
查看>>
AWK手册
查看>>
项目简介
查看>>
驼峰风格字符串转换为下滑线风格字符串
查看>>
ios图片倒影效果的实现
查看>>
SPSS Modeler K-Means聚类结果评价
查看>>
easyui left-tabs 左侧的tabs
查看>>
图论中DFS与BFS的区别、用法、详解?
查看>>