转载请标明出处: 本文出自:
#前言:
继 做了很多修改.期间有很多纠结的地方, 对比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 SparseArraymViews; 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 BaseActivityextends 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 TempletActivityextends 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.UIView
的View
来操作TempletActivity.
4.BaseActivity
与BaseFragment
,属于基类,无需关系Toolbar的情况.也就不需要ToolbarHelper
5.通过重写initToolbarLayout()
就能设置不同样式的Toolbar
,如果样式满足不了需求,可以直接继承BaseActivity,BaseFragment
来自定义
6.可以通过ToolbarHelper
获取mApplayout
,进行增删子View.以及设置属性.
7.可以通过ToolbarHelper
的findAppBarView(id)
获取mApplayout
中的子控件.
8.可以通过ToolbarHelper
的setScrollFlag(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 BaseActivityextends 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地址,时不时就更新
您的喜欢与回复是我最大的动力-_-