快速实现Fragment切换功能
2016-11-05 16:47
274 查看
1. 前言
一个app首页通常是使用Activity + Fragment的形式展示,控制Fragment的显示和隐藏基本有两种实现方法
ViewPager , 比如微信 , 优势是手势操作更加方便,官方提供了FragmentPagerAdapter可以很方便帮助我们实现数据加载(Fragment要使用懒加载的方式,避免浪费资源),劣势就是当你的第一个Fragment中已经使用了ViewPager,两层套一起事件会冲突,而且操作也不友好啦。
FragmentManager , 比如头条,针对使用ViewPager组合Fragment的问题,使用FragmentManager控制Fragment的显示和隐藏,不需要考虑懒加载的问题,不过不能支持滑动啦。
既然是经常使用的功能,自然要分离出来,避免下次做重复的工作,本文主要介绍这个功能的实现。
2. 最初的方案
刚开始的方案是定义了一个Activity的基类MultiFragmentActivity,在基类中实现切换Fragment的逻辑,想要实现该功能的Activity继承基类就可以实现切换功能。MultiFragmentActivity.java源代码,这种实现方式使用起来要更加简单,但是有个问题,整个项目通常会实现同一个基类来完成类似或者相同的功能,当然我们可以将MultiFragmentActivity继承自项目的基类,然后再继承MultiFragmentActivity,但是我的想法是能把这个功能放到Library中,方便以后使用,那就面临一个问题就是不能采用继承的方式。少用继承,多用组合,继承造成的问题就是耦合性太高,不方便分离功能,所以决定使用组合的方法重新设计,定义帮助类FragmentHelper,Activity可以持有FragmentHelper来完成Fragment的切换,具体的切换逻辑由FragmentHelper来处理。
3. 定义接口
首先定义FragmentOperator接口,借助该接口FragmentHelper连接持有它的Activityinterface FragmentOperator { /** * 获取放置fragment的控件id * * @return id */ int getFragmentContainerId(); /** * 构建fragment * * @param showItem 将要展示的fragment pos * @return fragment */ Fragment makeFragment(int showItem); /** * 进行转换之前做操作,动画之类的 * * @return FragmentTransaction */ void beginTransaction(FragmentTransaction transaction); /** * 同步选中之后的显示状态 * * @param selectImage 被选中的item */ void syncSelectState(int selectImage); /** * 当点击显示同一个 * * @param showItem 显示的item * @return 返回false表示忽略此次点击的切换 */ boolean whenShowSameFragment(int showItem); /** * 当点击显示的不是同一个 * * @param showItem 显示的item * @return 返回false表示忽略此次点击的切换 */ boolean whenShowNotSameFragment(int showItem); } // 一个简单封装 public static abstract class SimpleFragmentOperator implements FragmentOperator { @Override public boolean whenShowNotSameFragment(int showItem) { return true; } @Override public boolean whenShowSameFragment(int showItem) { return false; } @Override public void syncSelectState(int selectImage) { } @Override public void beginTransaction(FragmentTransaction transaction) { } }
4. 核心方法
使用tag作为标记添加fragment,避免重复创建private static final String FRAGMENT_ATG = "FragmentHelper"; private static final String ITEM_HIDE = "mHideItem"; private static final String ITEM_SHOW = "mShowItem"; private FragmentOperator operator; private Fragment mCurrentFragment; private FragmentManager mFragmentManager; private int mShowItem, mHideItem; private int mExactlyItem = 0; /** * 隐藏当前显示的fragment,显示将要显示的fragment * * @param hideItem 需要隐藏的fragment * @param showItem 需要显示的fragment * @param isOnCreate 是否是第一次从OnCreate中启动,点击都是false */ private void performSelectItem(int hideItem, int showItem, boolean isOnCreate) { // 获得将要显示页的tag String currentTag = getFragmentTag(hideItem); // 隐藏当前的的fragment FragmentTransaction transaction = mFragmentManager.beginTransaction(); operator.beginTransaction(transaction); // 第一次创建,一个都没有,不需要隐藏,直接显示 if (mFragmentManager.getFragments() == null) { mShowItem = showItem; mExactlyItem = showItem; mCurrentFragment = operator.makeFragment(showItem); transaction.add(operator.getFragmentContainerId(), mCurrentFragment, getFragmentTag(showItem)) .show(mCurrentFragment); } else { // 优化,如果被杀后再进来,全部的fragment都会被呈现显示状态,所以都隐藏一遍 if (isOnCreate && mFragmentManager.getFragments() != null) { for (Fragment fragment : mFragmentManager.getFragments()) { transaction.hide(fragment); } } else { // 正常按钮点击进入,隐藏上一个即可 Fragment lastFragment = mFragmentManager.findFragmentByTag(currentTag); if (lastFragment != null) { transaction.hide(lastFragment); } } // 获得将要显示页的tag String toTag = getFragmentTag(showItem); // find要显示的Fragment mCurrentFragment = mFragmentManager.findFragmentByTag(toTag); if (mCurrentFragment != null) { // 已经存在则显示 transaction.show(mCurrentFragment); } else { // 不存在则添加新的fragment mCurrentFragment = operator.makeFragment(showItem); if (mCurrentFragment != null) { transaction.add(operator.getFragmentContainerId(), mCurrentFragment, toTag); } } } // 同步状态 operator.syncSelectState(showItem); // 保存当前显示fragment的item mHideItem = hideItem; mShowItem = showItem; transaction.commitAllowingStateLoss(); }
5. 在Activty显示某个Fragment
在Activity中使用时只需要调用showFragment方法即可/** * 显示某个fragment * * @param showItem 显示的item */ public void showFragment(int showItem) { showFragment(showItem, false); } /** * 选中某一个fragment * * @param showItem 显示的item * @param isOnCreate 是否是第一次创 */ private void showFragment(int showItem, boolean isOnCreate) { if (showItem == mShowItem) { if (operator.whenShowSameFragment(showItem)) { performSelectItem(mExactlyItem, showItem, isOnCreate); mExactlyItem = showItem; } } else { performSelectItem(mExactlyItem, showItem, isOnCreate); mExactlyItem = showItem; } }
6. 优化
当Activity被回收时,记录上次的状态public void restoreFragmentHelper(Bundle save) { if (save != null) { mHideItem = save.getInt(ITEM_HIDE, 0); mShowItem = save.getInt(ITEM_SHOW, 0); } performSelectItem(mHideItem, mShowItem, true); } public void onSaveInstanceState(Bundle outState) { outState.putInt(ITEM_HIDE, mHideItem); outState.putInt(ITEM_SHOW, mShowItem); }
7. 使用
public class HomePageActivity extends BaseReaperActivity { private FragmentHelper fragmentHelper; private FragmentHelper.SimpleFragmentOperator operator = new FragmentHelper.SimpleFragmentOperator() { @Override public int getFragmentContainerId() { return R.id.home_container; } @Override public Fragment makeFragment(int showItem) { Fragment fragment = null; switch (showItem) { case 0: fragment = HomeVideoFunFragment.newInst(); break; case 1: fragment = HomeFunnyFragment.newInst(); break; case 2: fragment = HomeBeautyFragment.newInst(); break; case 3: fragment = HomeMineFragment.newInst(); break; } return fragment; } @Override public void beginTransaction(FragmentTransaction transaction) { super.beginTransaction(transaction); Logger.e("beginTransaction"); } @Override public void syncSelectState(int selectImage) { for (int i = 0; i < mBotTabsTv.size(); i++) { mBotTabsTv.get(i).setSelected(selectImage == i); } } @Override public boolean whenShowNotSameFragment(int showItem) { JCVideoPlayer.releaseAllVideos(); return super.whenShowNotSameFragment(showItem); } }; @Override public void onInitViews(View view, Bundle saveData) { super.onInitViews(view, saveData); fragmentHelper = new FragmentHelper(getSupportFragmentManager(), operator); fragmentHelper.showFragment(2); } @OnClick({R.id.home_recommend, R.id.home_album, R.id.home_search, R.id.home_mine}) public void click(View v) { int tag = Integer.parseInt(v.getTag().toString()); fragmentHelper.showFragment(tag); } @Override public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) { super.onSaveInstanceState(outState, outPersistentState); fragmentHelper.onSaveInstanceState(outState); } @Override public void onInitViews(View view, Bundle saveData) { super.onInitViews(view, saveData); fragmentHelper = new FragmentHelper(getSupportFragmentManager(), operator); fragmentHelper.showFragment(2); } }
8. 源代码
/** * Project : CommonLib * Package : com.march.lib.core.common * CreateAt : 2016/11/5 * Describe : 实现Fragment切换 * * @author chendong */ public class FragmentHelper { interface FragmentOperator { /** * 获取放置fragment的控件id * * @return id */ int getFragmentContainerId(); /** * 构建fragment * * @param showItem 将要展示的fragment pos * @return fragment */ Fragment makeFragment(int showItem); /** * 进行转换之前做操作,动画之类的 * * @return FragmentTransaction */ void beginTransaction(FragmentTransaction transaction); /** * 同步选中之后的显示状态 * * @param selectImage 被选中的item */ void syncSelectState(int selectImage); /** * 当点击显示同一个 * * @param showItem 显示的item * @return 返回false表示忽略此次点击的切换 */ boolean whenShowSameFragment(int showItem); /** * 当点击显示的不是同一个 * * @param showItem 显示的item * @return 返回false表示忽略此次点击的切换 */ boolean whenShowNotSameFragment(int showItem); } public static abstract class SimpleFragmentOperator implements FragmentOperator { @Override public boolean whenShowNotSameFragment(int showItem) { return true; } @Override public boolean whenShowSameFragment(int showItem) { return false; } @Override public void syncSelectState(int selectImage) { } @Override public void beginTransaction(FragmentTransaction transaction) { } } private static final String FRAGMENT_ATG = "FragmentHelper"; private static final String ITEM_HIDE = "mHideItem"; private static final String ITEM_SHOW = "mShowItem"; private FragmentOperator operator; private Fragment mCurrentFragment; private FragmentManager mFragmentManager; private int mShowItem, mHideItem; private int mExactlyItem = 0; public void restoreFragmentHelper(Bundle save) { if (save != null) { mHideItem = save.getInt(ITEM_HIDE, 0); mShowItem = save.getInt(ITEM_SHOW, 0); } performSelectItem(mHideItem, mShowItem, true); } public void onSaveInstanceState(Bundle outState) { outState.putInt(ITEM_HIDE, mHideItem); outState.putInt(ITEM_SHOW, mShowItem); } public FragmentHelper(FragmentManager mFragmentManager, FragmentOperator operator) { this.mFragmentManager = mFragmentManager; this.mFragmentManager = mFragmentManager; this.operator = operator; } /** * 显示某个fragment * * @param showItem 显示的item */ public void showFragment(int showItem) { showFragment(showItem, false); } /** * 选中某一个fragment,处理重复点击 * * @param showItem 显示的item * @param isOnCreate 是否是第一次创 */ private void showFragment(int showItem, boolean isOnCreate) { if (showItem == mShowItem) { if (operator.whenShowSameFragment(showItem)) { performSelectItem(mExactlyItem, showItem, isOnCreate); mExactlyItem = showItem; } } else { performSelectItem(mExactlyItem, showItem, isOnCreate); mExactlyItem = showItem; } } /** * 获取当前处于活动状态的fragment' * * @return fragment */ public Fragment getCurrentFragment() { return mCurrentFragment; } /** * 隐藏当前显示的fragment,显示将要显示的fragment * * @param hideItem 需要隐藏的fragment * @param showItem 需要显示的fragment * @param isOnCreate 是否是第一次从OnCreate中启动,点击都是false */ private void performSelectItem(int hideItem, int showItem, boolean isOnCreate) { // 获得将要显示页的tag String currentTag = getFragmentTag(hideItem); // 隐藏当前的的fragment FragmentTransaction transaction = mFragmentManager.beginTransaction(); operator.beginTransaction(transaction); // 第一次创建,一个都没有,不需要隐藏,直接显示 if (mFragmentManager.getFragments() == null) { mShowItem = showItem; mExactlyItem = showItem; mCurrentFragment = operator.makeFragment(showItem); transaction.add(operator.getFragmentContainerId(), mCurrentFragment, getFragmentTag(showItem)) .show(mCurrentFragment); } else { // 优化,如果被杀后再进来,全部的fragment都会被呈现显示状态,所以都隐藏一遍 if (isOnCreate && mFragmentManager.getFragments() != null) { for (Fragment fragment : mFragmentManager.getFragments()) { transaction.hide(fragment); } } else { // 正常按钮点击进入,隐藏上一个即可 Fragment lastFragment = mFragmentManager.findFragmentByTag(currentTag); if (lastFragment != null) { transaction.hide(lastFragment); } } // 获得将要显示页的tag String toTag = getFragmentTag(showItem); // find要显示的Fragment mCurrentFragment = mFragmentManager.findFragmentByTag(toTag); if (mCurrentFragment != null) { // 已经存在则显示 transaction.show(mCurrentFragment); } else { // 不存在则添加新的fragment mCurrentFragment = operator.makeFragment(showItem); if (mCurrentFragment != null) { transaction.add(operator.getFragmentContainerId(), mCurrentFragment, toTag); } } } // 同步状态 operator.syncSelectState(showItem); // 保存当前显示fragment的item mHideItem = hideItem; mShowItem = showItem; transaction.commitAllowingStateLoss(); } private String getFragmentTag(int item) { return FRAGMENT_ATG + item; } }
相关文章推荐
- Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)
- 使用Fragment实现底部菜单栏功能,并实现左右滑动切换
- Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- Fragment界面切换之Logo功能的实现
- Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- Android开发使用Activity嵌套多个Fragment实现横竖屏切换功能的方法
- 通过fragment实现tabhost切换页面的功能
- android Fragment实现Tab功能(fragment相互切换时,可保存之前状态)
- Android使用Fragment来实现ViewPager的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- viewpager+fragment的懒加载实现微信点击和滑动切换功能(切换效果)
- Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- 【转】Android使用Fragment来实现ViewPager的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- android Fragment实现Tab功能(fragment相互切换时,可保存之前状态)
- Android使用Fragment来实现ViewPager的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信