Fragment 嵌套Fragment注意事项
来源:互联网 发布:windows 7默认壁纸 编辑:程序博客网 时间:2024/05/22 03:30
最近项目新功能需要在垂直方方向可以循环滚动,并且水平方向也可以水平循环滚动,并且可以定位到指定item上。很自然的想到了ViewPager和 VerticalViewPager来解决项目需求,UI的大致结构如下
以下垂直方向滚动的ViewPager所在的Fragment成为A,水平方向滚动的ViewPager所在的Fragment成为B!
1、循环滚动的实现
要实现循环滚动的原理很简单,就是设置item数量为无限大或者为一个很大的数值,然后设置currentItem为该数值的一半这样就可以实现上下(左右)循环滚动了!在PagerAdaper上修改方法:
@Override public int getCount() { return Integer.MAX_VALUE; }
2、定位到指定item功能实现
从Fragment到Fragment通信,这里选择的是EventBus这个插件!
- .在A上监听水平垂直变化的Event,接收到消息后定位到指定行,并且发送水平方向的移动Event
在B上监听水平移动的Event,接收到消息后定位到指定列
这样定位到指定item的功能就实现了!
A:
@Subscribe(threadMode = ThreadMode.MAIN) public void onAnimationEvent(RowEvent rowEvent) { int index = viewPager.getCurrentItem() - viewPager.getCurrentItem() % rowEvent.allRows; viewPager.setCurrentItem(index + rowEvent.row); final Intent intent = new Intent(ChallengeItemFragment.COLUMN_ACTION); intent.putExtra("stageId", rowEvent.stageId); intent.putExtra("column", rowEvent.column); viewPager.postDelayed(new Runnable() { @Override public void run() { LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(intent); } }, 250); //通知变化// EventBus.getDefault().post(new ColumnEvent(rowEvent.row, rowEvent.column, rowEvent.stageId)); }
B:
@Subscribe(threadMode = ThreadMode.MAIN) public void onAnimationEvent(ColumnEvent columnEvent) { if (columnEvent.stageId != stage.stageId) { return; } int index = challengeItemViewpager.getCurrentItem() - challengeItemViewpager.getCurrentItem() % stage.challengeList.size(); challengeItemViewpager.setCurrentItem(index + columnEvent.column); }
以上为项目背景以及基本使用介绍,下面进入主题:
在测试的时候发现一个很奇怪的现象,从菜单进入该页面,并且该页面每次都是重新初始化的,在定位时收到了重复的水平方向定位消息,以下为log截图
并且每从菜单进入一次,重复测试就+1。
经过debug以及log发现,B的实例对象一直存在,就算从菜单进入,并且重新初始化了A也是一样。
作为ViewPager的切入点,当然就是Adapter了,因为项目统一使用的是Fragment而不是v4包的Fragment,所以PagerAdaper是拷贝FragmentStatePagerAdapter的,getItem上的主要方法实现如下
public android.app.Fragment getItem(int position) { int oriPosition = position; position = position % data.stageList.size(); B itemFragment = new B(); Bundle param = new Bundle(); param.putParcelable(B.EXTRA_STAGE, stage); param.putBoolean(B.EXTRA_LOCKED, isLocked); itemFragment.setArguments(param); return itemFragment; }
经过分析发现最终定位到mFragmentManager。在实例化Adapter时,传入的是getFragmentManger(),因为fragmentManager的生命周期是跟随Activity的,所以就算A重新实例化,使用的FragmentManager也是相同的,并且在Adapter上的实现:
public Object instantiateItem(ViewGroup container, int position) { // If we already have this item instantiated, there is nothing // to do. This can happen when we are restoring the entire pager // from its saved state, where the fragment manager has already // taken care of restoring the fragments we previously had instantiated. if (mFragments.size() > position) { Fragment f = mFragments.get(position); if (f != null) { return f; } } if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } Fragment fragment = getItem(position); if (mSavedState.size() > position) { Fragment.SavedState fss = mSavedState.get(position); if (fss != null) { fragment.setInitialSavedState(fss); } } while (mFragments.size() <= position) { mFragments.add(null); } fragment.setMenuVisibility(false); fragment.setUserVisibleHint(false); mFragments.set(position, fragment); mCurTransaction.add(container.getId(), fragment); return fragment; }
mCurTransaction.add(container.getId(), fragment);实例化后的Fragment加入FragmenManager管理!那么足可以说明每次实例化A后,其实之前已经添加到FragmenManager的B对象时没有销毁的,这就导致了每次从菜单进入A,水平定位上总是收到重复消息数量+1
既然发现了问题,那么就很好解决了,在A destory之前清除已经在FragmenManager上的B对象即可!在Adapter上添加:
public void clearFragments() { if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } for (Fragment fragment : mFragments) { if (fragment != null && fragment.isAdded()) { mCurTransaction.remove(fragment); } } mCurTransaction.commitAllowingStateLoss(); }
@Override public void onDestroyView() { EventBus.getDefault().unregister(this); challengeAdapter.clearFragments(); super.onDestroyView(); }
这样此问题完美解决了!
在Fragment内使用FragmentManager推荐使用的是 getChildFragmentManager()但是此方法是在API17上添加的,所以还必须使用v4的Fragment。至于在v4.Fragment上是否会出现此问题,等以后遇到了再去研究!!
- Fragment 嵌套Fragment注意事项
- Fragment 嵌套Fragment注意事项
- 在fragment中嵌套fragment的注意事项
- Fragment嵌套Fragment
- fragment 嵌套fragment
- Fragment 嵌套 Fragment 问题
- Fragment中嵌套Fragment
- Fragment里面嵌套Fragment
- Fragment嵌套Fragment
- Fragment嵌套
- fragment 嵌套
- fragment嵌套fragment的管理
- Fragment中控制嵌套Fragment
- 关于Fragment里面嵌套fragment
- Fragment中嵌套Fragment问题
- Fragment嵌套Fragment要用getChildFragmentManager
- 在fragment里面嵌套fragment
- Fragment嵌套Fragment要用getChildFragmentManager
- viewpager实现轮播图效果
- LeetCode - 234. Palindrome Linked List
- 研发工作中芯片选型需要考虑的问题
- 归并排序
- Android应用性能优化之使用SparseArray
- Fragment 嵌套Fragment注意事项
- Linux学习之路--启动VNC服务
- 从tcp原理角度理解Broken pipe和Connection reset by peer的区别
- Thinking in Java 第6章 访问权限控制 【Java 访问权限修饰词】
- 序列化XML的类。包括向SQL传XML数据
- dojo学习之1
- FAQ-json字符串和json对象相互转换
- 371. Sum of Two Integers(Leetcode)
- GMS介绍