https://github.com/yaozs/YzsLib
https://github.com/yaozs/YzsBaseActivity
有人说现在流行的是mvp架构的程序,但我想问你,mvp架构的目的是什么呢? 他就是为了让代码的阅读性和可拓展性更强,同样,我写这篇博客的目的也是,而且我认为,在一些界面,根本就没必要使用mvp架构,架构是人写出来的,是死的东西,而人是活的,不要舍本逐末。当然,我也知道mvp架构的好处,所以,在这里提一句,我的这个封装是为了让一些简单的界面,常用的界面更加简洁的书写出来。没有必要说我这个app的架构是mvp就全用他。
接下来我们开始封装我们这种简单的界面,首先我们要弄清,我们需要在最基本的baseactivity里封装什么呢?
跳转方法接收传值方法Android 4.4版本以上沉浸式的封装Toolbar的封装界面之间消息传递的封装(EventBus)加载中动画的封装有了这些封装,我们在基本的activity中就减少了很多代码,比如加载动画,我们封装完成之后,可能只需要一个方法的调用,loading界面就出现了。
下面把我写的封装拿出来,给大家做一下参考,抛砖引玉。
1.跳转方法
/** * 界面跳转 * * @param clazz 目标Activity */ PRotected void readyGo(Class<?> clazz) { readyGo(clazz, null); } /** * 跳转界面, 传参 * * @param clazz 目标Activity * @param bundle 数据 */ protected void readyGo(Class<?> clazz, Bundle bundle) { Intent intent = new Intent(this, clazz); if (null != bundle) intent.putExtras(bundle); startActivity(intent); } /** * 跳转界面并关闭当前界面 * * @param clazz 目标Activity */ protected void readyGoThenKill(Class<?> clazz) { readyGoThenKill(clazz, null); } /** * @param clazz 目标Activity * @param bundle 数据 */ protected void readyGoThenKill(Class<?> clazz, Bundle bundle) { readyGo(clazz, bundle); finish(); } /** * startActivityForResult * * @param clazz 目标Activity * @param requestCode 发送判断值 */ protected void readyGoForResult(Class<?> clazz, int requestCode) { Intent intent = new Intent(this, clazz); startActivityForResult(intent, requestCode); } /** * startActivityForResult with bundle * * @param clazz 目标Activity * @param requestCode 发送判断值 * @param bundle 数据 */ protected void readyGoForResult(Class<?> clazz, int requestCode, Bundle bundle) { Intent intent = new Intent(this, clazz); if (null != bundle) { intent.putExtras(bundle); } startActivityForResult(intent, requestCode); }2.接收传值方法
/** * Bundle 传递数据 * * @param extras */ protected abstract void getBundleExtras(Bundle extras); @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //当手机版本大于等于4.4时才会使用的方法,沉浸式 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { setTranslucentStatus(true); //这个对象不是android api中自带的,是我们自己写的 SystemBarTintManager tintManager = new SystemBarTintManager(this); tintManager.setStatusBarTintEnabled(true); tintManager.setStatusBarTintResource(R.color.colorPrimaryDark);//通知栏所需颜色 } Bundle extras = getIntent().getExtras(); if (null != extras) { getBundleExtras(extras); } EventBus.getDefault().register(this); initContentView(savedInstanceState); mToolbar = (Toolbar) findViewById(R.id.toolbar); if (null != mToolbar) { setSupportActionBar(mToolbar); getSupportActionBar().setDisplayShowTitleEnabled(false); initTitle(); } initView(); initLogic(); } /** * 替代onCreate的使用 */ protected abstract void initContentView(android.os.Bundle bundle); /** * 初始化view */ protected abstract void initView(); /** * 初始化逻辑 */ protected abstract void initLogic();这样封装base,当使用者继承baseactivity时,会强制实现几个方法,而每个方法都有他自己的功能,这样就会使Activity的使用者使用起来更加清晰,即使维护者与开发者不是同一个人,其逻辑的清晰程度也会让他快速上手。
3.Android 4.4版本以上沉浸式的封装
在2中已经出现了,就是这个方法
//当手机版本大于等于4.4时才会使用的方法,沉浸式 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { setTranslucentStatus(true); //这个对象不是android api中自带的,是我们自己写的 SystemBarTintManager tintManager = new SystemBarTintManager(this); tintManager.setStatusBarTintEnabled(true); tintManager.setStatusBarTintResource(R.color.colorPrimaryDark);//通知栏所需颜色 }SystemBarTintManager 他是怎么写的呢,这个不在我们今天要讨论的范围,所以请直接参考
YzsBaseActivity https://github.com/yaozs/YzsBaseActivity
我的这个开源项目,里面有他的源码。
4.Toolbar的封装
同样是在onCreate方法中
5.界面之间消息传递的封装(EventBus)
mToolbar = (Toolbar) findViewById(R.id.toolbar); if (null != mToolbar) { setSupportActionBar(mToolbar); getSupportActionBar().setDisplayShowTitleEnabled(false); initTitle(); } /** * 初始化toolbar */ protected void initTitle() { title = (TextView) findViewById(R.id.toolbar_title); back = (ImageView) findViewById(R.id.toolbar_back); iv_menu = (ImageView) findViewById(R.id.toolbar_iv_menu); tv_menu = (TextView) findViewById(R.id.toolbar_tv_menu); if (null != back) { back.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); } }在这里说明下,我在我的库中findid不是吧他写死在xml中,而是在valuse中的创建了ids文件,
在这里把他引用出来,而在我们使用过程中如果你用到了,在你的xml把这个id使用出来就可以(id一致),如果不用,过着有更复杂的写法,将initTitle这个方法重写,就可以。
6.加载中动画的封装
在我的baseActivity框架中,我封装成的是一个loadingdialog,一个仿win10的loading,一个是自己写的动画
同样在,其他地方调用loading时,也是一句话调用 LoadingDialog.showLoadingDialog(this, type, str, drawable);使用这个方法。具体使用请参考yzsbaseactivity源码。
这样的界面经常会在我们的app中出现,而我们做了什么封装呢,在这里首先声明一下我使用的几个库
通过对这几个库的封装让我们可以更加简单的写出一个界面
当我们封装这样的Activity时,涉及到一个东西就是泛型,为什么是泛型呢,因为在这样的界面,他就是一个重复的列表展示,所以他们的对象都是同一个对象,所以我们在类创建时,就要把他声明出来,声明之后,我们在其他的地方就可以直接调用了。
public abstract class YzsBaseListActivity<T> extends YzsBaseActivity同样,为了我们这样的界面可以适配更多的类型,我们使用recyclerview,为什么使用他呢,因为recyclerview的功能更加强大,他的强大之处在于这几个方面
可以实现listview,gridview,瀑布流多种布局回收机制比listview和gridview更加优秀可定制性更加强大下面,开始将BaseRecyclerViewAdapterHelper封装到我们的Activity中,这里最关键的地方就是一个问题,一般情况下我们是自己写adapter,单独的写出一个类出来,我们要做的就是把adapter封装在Activity中,让使用者不用关心adapter的创建,直接去使用它,但是adapter又需要list的数据类型,这样问题就回来了,我们最开始就声明了一个泛型数据类,我们在写listActivity时,写出了数据类型就可以直接使用了,就像这样
/** * Author: 姚智胜 * Version: V1.0版本 * Description: list的activity的封装使用 * Date: 2017/2/18 */public class ListActivity extends YzsBaseListActivity<DemoListBean> { private static final String TAG = "ListActivity"; /** * 初始化子布局 * 在这个方法里处理的是recyclerview的所有的初始化, * 包括对他的展示形式,是list或grid或瀑布流 */ @Override protected void initItemLayout() { //调用该方法设置adapter的子布局 setLayoutResId(R.layout.item_list_demo); } /** * adapter内部布局的处理 * @param baseViewHolder BaseViewHolder * @param demoListBean */ @Override protected void MyHolder(BaseViewHolder baseViewHolder, DemoListBean demoListBean) { } @Override protected void initContentView(Bundle bundle) { } @Override protected void initLogic() { } @Override protected void getBundleExtras(Bundle extras) { } @Override protected void onEventComing(EventCenter center) { }}那么YzsBaseListActivity怎么写的呢,我们想一下,recyclerview需要的设置都有哪些呢?设置他的布局方式,同时,是否打开他的baseadapter中为我们提供的loadmore方法(这个方法在新版本的adapter有些变化,但是不影响我们的使用,我们只需在base中改变一下就可以了)
public abstract class YzsBaseListActivity<T> extends YzsBaseActivity { private static final String TAG = "YzsBaseListActivity"; /** * 普通list布局 */ protected static final int LINEAR_LAYOUT_MANAGER = 0; /** * grid布局 */ protected static final int GRID_LAYOUT_MANAGER = 1; /** * 瀑布流布局 */ protected static final int STAGGERED_GRID_LAYOUT_MANAGER = 2; /** * 默认为0单行布局 */ private int mListType = 0; /** * 排列方式默认垂直 */ private boolean mIsVertical = true; /** * grid布局与瀑布流布局默认行数 */ private int mSpanCount = 1; protected RecyclerView mRecyclerView; protected YzsListAdapter mAdapter; /** * 子布局id */ private int layoutResId = -1; @Override protected void initView() { initItemLayout(); mRecyclerView = (RecyclerView) findViewById(R.id.yzs_base_list); chooseListType(mListType, mIsVertical); if (-1 == layoutResId) { throw new RuntimeException("layoutResId is null!"); } mAdapter = new YzsListAdapter(layoutResId, new ArrayList<T>()); mRecyclerView.setAdapter(mAdapter); } /** * 设置子布局layout * * @param layoutResId 子布局layout */ public void setLayoutResId(@LayoutRes int layoutResId) { this.layoutResId = layoutResId; } /** * 初始化子布局 */ protected abstract void initItemLayout(); /** * 是否打开加载更多 */ protected void openLoadMoreSize(boolean loadMore) { mAdapter.loadMoreEnd(loadMore); } /** * @param type 布局管理type * @param isVertical 是否是垂直的布局 ,true垂直布局,false横向布局 */ protected void setListType(int type, boolean isVertical) { mListType = type; mIsVertical = isVertical; } protected void setSpanCount(int spanCount) { if (spanCount > 0) mSpanCount = spanCount; } /** * @param listType 选择布局种类 */ private void chooseListType(int listType, boolean isVertical) { switch (listType) { case LINEAR_LAYOUT_MANAGER: //设置布局管理器 LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); linearLayoutManager.setOrientation(isVertical ? LinearLayoutManager.VERTICAL : LinearLayoutManager.HORIZONTAL); mRecyclerView.setLayoutManager(linearLayoutManager); break; case GRID_LAYOUT_MANAGER: GridLayoutManager gridLayoutManager = new GridLayoutManager(this, mSpanCount); gridLayoutManager.setOrientation(isVertical ? GridLayoutManager.VERTICAL : GridLayoutManager.HORIZONTAL); mRecyclerView.setLayoutManager(gridLayoutManager); break; case STAGGERED_GRID_LAYOUT_MANAGER: //设置布局管理器 StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager (mSpanCount, isVertical ? StaggeredGridLayoutManager.VERTICAL : StaggeredGridLayoutManager.HORIZONTAL); mRecyclerView.setLayoutManager(staggeredGridLayoutManager); break; default: //设置布局管理器 LinearLayoutManager layoutManager = new LinearLayoutManager(this); layoutManager.setOrientation(isVertical ? LinearLayoutManager.VERTICAL : LinearLayoutManager.HORIZONTAL); mRecyclerView.setLayoutManager(layoutManager); break; } } /** * adapter内的处理 * * @param baseViewHolder BaseViewHolder * @param t 泛型T */ protected abstract void MyHolder(BaseViewHolder baseViewHolder, T t); public class YzsListAdapter extends BaseQuickAdapter<T, BaseViewHolder> { public YzsListAdapter(int layoutResId, List<T> data) { super(layoutResId, data); } @Override protected void convert(BaseViewHolder baseViewHolder, T t) { MyHolder(baseViewHolder, t); } }}我们这样封装完成,在我们自己的Activity中,在这个方法initItemLayout()中,把reyclerview的所有初始化写完就可以了,剩下的在MyHolder(BaseViewHolder baseViewHolder, T t);这个方法中处理子布局就可以了,说的极限点,现在继承baselistactivity之后,最简单的list界面,你最少只需要写5到8行设置属性就搞定了,剩下的全是adapter里面的处理了,是不是简化了很多代码,同时让代码更加清晰了。
这也是我写这个库的目的,就是方便,就是要懒。
同样,basehomeActivity使用的是FlycoTabLayout这个开源库,不知道的可以去github搜索一下,下面来说下这也首页的封装思想,抛开那写定制度特别高的app,一般的app在首页都是在底部有几个导航按钮,上面是fragment进行切换,那么我们要封装到什么程度呢??
就这些代码,我们首页activity就写完了,同时没有你们所说的fragment覆盖问题,在这里要提一句,fragment重叠的问题是因为google原来fragment库的一个bug或者不能说是bug的问题,但他已经在api25的lib里修复了,我们这个库不管你用api几都会不出现这个问题,因为他是可以处理的,在这向大家推荐一个fragmentation ,上面我也提到,在这里使用,他提供了fragment的懒加载方法等非常使用的东西,有兴趣的可以去看看。
同时,我们的首页有两种形式,一种是可滑动的viewpager,一种是不支持滑动的framelayout格式,在我们的封装中,只需使用ids中指定的id就可以了,viewpager使用viewpager的id,framelayout使用它的id,程序会自动判断。是不是很方便!!
下面上basehome代码
public abstract class YzsBaseHomeActivity extends YzsBaseActivity { private static final String TAG = "YzsBaseHomeActivity"; /** * title文字部分 */ private String[] mTitles; /** * 未选中图标数组 */ private int[] mIconUnSelectIds; /** * 选中图标数组 */ private int[] mIconSelectIds; /** * fragment集合 */ protected YzsBaseFragment[] mFragments; /** * 导航条 */ protected CommonTabLayout mTabLayout; /** * 图标信息对象 */ private ArrayList<CustomTabEntity> mTabEntities = new ArrayList<>(); protected ViewPager mViewPager; protected FrameLayout mFrameLayout; private Bundle bundle; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setBundle(savedInstanceState); } @Override protected void initView() { mTabLayout = (CommonTabLayout) findViewById(R.id.yzs_base_tabLayout); mViewPager = (ViewPager) findViewById(R.id.yzs_base_tabLayout_viewPager); mFrameLayout = (FrameLayout) findViewById(R.id.yzs_base_tabLayout_frameLayout); initTab(); if (null == mFragments || mFragments.length == 0) { throw new RuntimeException("mFragments is null!"); } initTabEntities(); if (null == mTabLayout) { throw new RuntimeException("CommonTabLayout is null!"); } if (null == mTitles || mTitles.length == 0) { mTabLayout.setTextsize(0); } if (null != mViewPager) { Log.e(TAG,"Choose_ViewPager"); initViewpagerAdapter(); } else { initFragments(); Log.e(TAG,"Choose_frameLayout"); } setTabSelect(); } /** * 初始化图标图片文字fragment数据 */ private void initTabEntities() { if (null == mFragments || mFragments.length == 0 || mFragments.length != mIconSelectIds.length || mFragments.length != mIconUnSelectIds.length) { throw new RuntimeException("mFragments is null!or Fragments and the number of ICONS do not meet"); } for (int i = 0; i < mFragments.length; i++) { mTabEntities.add(new TabEntity(mTitles == null ? "" : mTitles[i], mIconSelectIds[i], mIconUnSelectIds[i])); } mTabLayout.setTabData(mTabEntities); } /** * 初始化Fragments */ private void initFragments() { //加载mFragments if (getBundle() == null) { //加载mFragments loadMultipleRootFragment(R.id.yzs_base_tabLayout_frameLayout, 1, mFragments); } else { // 这里库已经做了Fragment恢复,所有不需要额外的处理了, 不会出现重叠问题 for (int i = 0; i < mFragments.length; i++) { Log.e(TAG,"initFragments" + i); mFragments[i] = findFragment(mFragments[i].getClass()); } } } /** * 初始化viewpager的adapter */ private void initViewpagerAdapter() { mViewPager.setAdapter(new MyPagerAdapter(getSupportFragmentManager())); mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { mTabLayout.setCurrentTab(position); } @Override public void onPageScrollStateChanged(int state) { } }); } /** * 为mTabLayout */ private void setTabSelect() { Log.e(TAG,"setTabSelect"); mTabLayout.setOnTabSelectListener(new OnTabSelectListener() { @Override public void onTabSelect(int position) { if (null != mViewPager) { mViewPager.setCurrentItem(position); } else { int toDoHidden = -1; for (int i = 0; i < mFragments.length; i++) { if (!mFragments[i].isHidden()) { toDoHidden = i; Log.e(TAG,"查找显示中的fragment-------" + toDoHidden); } } Log.e(TAG,"选中的fragment-------" + position); Log.e(TAG,"确定显示中的fragment-------" + toDoHidden); showHideFragment(mFragments[position], mFragments[toDoHidden]); } } @Override public void onTabReselect(int position) { if (position == 0) { Log.e(TAG,"再次选中项" + position); } } }); } /** * 设置TabLayout属性,所有关于TabLayout属性在这里设置 */ protected abstract void initTab(); /** * 获取Fragment数组 * * @return mFragments */ public YzsBaseFragment[] getmFragments() { return mFragments; } /** * 放入Fragment数组(必须继承YzsBaseFragment) * * @param mFragments */ public void setmFragments(YzsBaseFragment[] mFragments) { this.mFragments = mFragments; } /** * 获取选中图标数组 * * @return mIconSelectIds */ public int[] getmIconSelectIds() { return mIconSelectIds; } /** * 放入选中图标数组 * * @param mIconSelectIds */ public void setmIconSelectIds(int[] mIconSelectIds) { this.mIconSelectIds = mIconSelectIds; } /** * 获取未选中图标数组 * * @return mIconUnSelectIds */ public int[] getmIconUnSelectIds() { return mIconUnSelectIds; } /** * 放入未选中图标数组 * * @param mIconUnSelectIds */ public void setmIconUnSelectIds(int[] mIconUnSelectIds) { this.mIconUnSelectIds = mIconUnSelectIds; } /** * 获取mTitles数组 * * @return mTitles */ public String[] getmTitles() { return mTitles; } /** * 放入mTitles数组 * * @param mTitles */ public void setmTitles(String[] mTitles) { this.mTitles = mTitles; } public Bundle getBundle() { return bundle; } public void setBundle(Bundle bundle) { this.bundle = bundle; } private class MyPagerAdapter extends FragmentPagerAdapter { public MyPagerAdapter(FragmentManager fm) { super(fm); } @Override public int getCount() { return mFragments.length; } @Override public CharSequence getPageTitle(int position) { return mTitles == null ? "" : mTitles[position]; } @Override public Fragment getItem(int position) { return mFragments[position]; } }}https://github.com/yaozs/YzsLib
https://github.com/yaozs/YzsBaseActivity
下次再见嘿嘿 (^o^)/YES!
新闻热点
疑难解答