参考地址:http://blog.csdn.net/wangjinyu501/article/details/8169924
ViewPager
PagerAdapter
PageAdapter 是 ViewPager 的支持者,ViewPager 将调用它来取得所需显示的页,而 PageAdapter 也会在数据变化时,通知 ViewPager。这个类也是FragmentPagerAdapter 以及 FragmentStatePagerAdapter 的基类。如果继承自该类,至少需要实现 instantiateItem(), destroyItem(), getCount() 以及 isViewFromObject()。
FragmentPagerAdapter
ViewPager中的Fragment保存:
package com.toutouunion.adapter; import java.util.List; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.view.ViewGroup; /** * @author XianFeng * @createdTime 2015年4月17日 下午3:00:39 * @usage 找达人适配器 * */ public class TalentFragmentAdapter extends FragmentPagerAdapter { private FragmentManager fManager; private List
fragmentsList; public TalentFragmentAdapter(FragmentManager fm, List fragments) { super(fm); this.fManager = fm; this.fragmentsList = fragments; } @Override public Fragment getItem(int arg0) { return fragmentsList.get(arg0); } @Override public int getCount() { return fragmentsList.size(); } @Override public Object instantiateItem(ViewGroup container, int position) { Fragment fragment = (Fragment) super.instantiateItem(container, position); this.fManager.beginTransaction().show(fragment).commit(); return fragment; } @Override public void destroyItem(ViewGroup container, int position, Object object) { Fragment fragment = fragmentsList.get(position); fManager.beginTransaction().hide(fragment).commit(); } }
FragmentStatePagerAdapter
ViewPager定义了一个:
private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES;默认值 是1,这表示你的预告加载的页面数量是1,假设当前有四个Fragment的tab,显示一个,预先加载下一个.这样你在移动前就已经加载了下一个界面,移动时就可以看到已经加载的界面了。
打印日志可以看到onActivityCreated等方法在初始化第一个Fragment完成后就会初始化下一个Fragment.
提供的公共方法源码如下:
从这个方法来看,不管你设置什么值,至少会预先加载下一个Fragment,你想预先加载几个就可以传入相应的参数.public void setOffscreenPageLimit(int limit) { if (limit < DEFAULT_OFFSCREEN_PAGES) { Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " + DEFAULT_OFFSCREEN_PAGES); limit = DEFAULT_OFFSCREEN_PAGES; } if (limit != mOffscreenPageLimit) { mOffscreenPageLimit = limit; populate(); } }
这种情况如音乐播放时,如果有自动加载歌词就可以使用了.
如果你的界面需要加载一些大量的数据,但你不想预先加载下一个界面(需要网络或耗时的操作),使用ViewPager却很无耐.特别是下一个界面有可能你一段很长时间不会使用到,如我开发的微博,在显示主页后我不想立即加载下一个界面,因为都有ListView,如果我不访问它,就不必加载无用的资源.
可以通过修改这个值,但有,修改后就会有一个麻烦的地方,因为移动时不会预先加载下一个界面的关系,所以会看到一片黑色的背景.
如果不介意黑色背景,可以覆盖这个类,然后定义默认的加载数量为0
private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES=0;就是不预先加载下一个界面.
如果想预加载,可以使用原来的ViewPager,或这里直接改为mOffscreenPageLimit=你要加载的数量。
由于sdk的更新问题,不是所有v4 support都适合的,v17时就换了
ViewPager切换动画教程:
http://blog.csdn.net/lmj623565791/article/details/40411921
http://blog.csdn.net/lmj623565791/article/details/38026503
官方解释:
The definition of
getChildFragmentManager()
is:Return a private FragmentManager for placing and managing Fragments inside of this Fragment.
Meanwhile the definition of
getFragmentManager()
(or in this casegetSupportFragmentManager()
) is:Return the FragmentManager for interacting with fragments associated with this fragment's activity.
Basically, the difference is that Fragment's now have their own internal
FragmentManager
that can handle Fragments. The child FragmentManager is the one that handles Fragments contained within only the Fragment that it was added to. The other FragmentManager is contained within the entireActivity
.In this case, what I'm guessing is you've added the Fragments to the Activity's FragmentManager. You get the child FragmentManager which doesn't contain what you are looking for. Thus you get the exception because it can't find the Fragment with the given ID because it's in a different FragmentManager.
所以,在Fragment中嵌套Fragment时,一定要使用 getChildFragmentManager();否则,会在ViewPager中出现fragment不会加载的情况,即fragment出现空白页的情况!
可以参看附件:尝试将HomeFragment中的72行中的getChildFragmentManager()改为getFragmentManager(),然后运行,点击其他底部tab之后,在返回第一个tab,可以看到fragment不加载的情况!
参考附件:http://download.csdn.net/detail/wenbitianxiafeng/7858269
1.Fragment虽然有onResume和onPause的,但是这两个方法是Activity的方法,调用时机也是与Activity相同。
2.通过阅读ViewPager和PageAdapter相关的代码,切换Fragment实际上就是通过设置setUserVisibleHint和
setMenuVisibility来实现的,调用这个方法时并不会释放掉Fragment(即不会执行onDestoryView)。
3.由于setUserVisibleHint优于onCreate调用,所以当onCreate调用完毕setUserVisibleHint就不会触发,这时需
要在首个显示的fragment(或者Activity中切换显示Fragment的相应地方)调用setUserVisibleHint方法,然后在对应
Fragment中重写(Override)setUserVisibleHint方法即可。
简单使用示例如下,代码中包含注释:
布局文件
适配器
效果如/** * 实现一个PagerAdapter内部类 * * @author Administrator * */ private class MyPageAdapter extends PagerAdapter { String[] titles; List
views; public MyPageAdapter(String[] titles, List views) { this.titles = titles; this.views = views; } /** * 要显示的页面的个数 */ @Override public int getCount() { return views == null ? 0 : views.size(); } /** * 获取一个指定页面的title描述 如果返回null意味着这个页面没有标题,默认的实现就是返回null * * 如果要显示页面上的title则此方法必须实现 */ @Override public CharSequence getPageTitle(int position) { return titles[position]; } /** * 创建指定position的页面。这个适配器会将页面加到容器container中。 * * @param container * 创建出的实例放到container中,这里的container就是viewPager * @return 返回一个能表示该页面的对象,不一定要是view,可以其他容器或者页面。 */ @Override public Object instantiateItem(ViewGroup container, int position) { // 必须要把创建的对象先添加到容器中,再返回。一般简单的adapter直接就返回显示的界面就完事了。 container.addView(views.get(position)); return views.get(position); } /** * 此方法会将容器中指定页面给移除 该方法中的参数container和position跟instantiateItem方法中的内容一致 * * @param object * 这个object 就是 instantiateItem方法中返回的那个Object */ @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(views.get(position)); } /** * 这个方法就是比较一下容器中页面和instantiateItem方法返回的Object是不是同一个 * * @param arg0 * ViewPager中的一个页面 * @param arg1 * instantiateItem方法返回的对象 */ @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } } pagerTabStrip.setTabIndicatorColor(int);可以改变导航条的颜色
pagerTabStrip.setTextColor(color);可以改变导航文字的颜色,字体大小类似TextView的修改。但是暂时实现不了如下效果图:控制文字和indicator的位置,常使用library——Android ViewPagerIndicator
1.FragmentTransaction.commitAllowingStateLoss()问题
官方文档介绍:
Like
commit()
but allows the commit to be executed after an activity's state is saved. This is dangerousbecause the commit can be lost if the activity needs to later be restored from its state, so this should
only be used for cases where it is okay for the UI state to change unexpectedly on the user.
类似于commit()方法,但是commit在Activity的onSaveInstanceState(Bundle outState)方法之后调用会出错:
IllegalStateException: Can not perform this action after onSaveInstanceState
解决上述错误办法:将commit()方法替换成commitAllowingStateLoss()方法即可!
参考博客:http://blog.csdn.net/harvic880925/article/details/38521865
解决方案两种:
第一种:
重写PagerAdapter的getItemPosition方法,如下:
public int getItemPosition(Object object) {
return POSITION_NONE;
}
这样,在调用notifyDataSetChanged方法的时候,ViewPager会remove掉所有的view,然后重新加载,在视图内容比较复杂的情况下,这种解决方案效率低下。
在PagerAdapter的instantiateItem()方法中,使用setTag()为需要改变的view添加tag,当需要改变ViewPager内容时,只需要通过findViewByTag()方法找到对应的view,修改即可。
相比第一种方案,此方案更加灵活和高效。
http://stackoverflow.com/questions/7263291/viewpager-pageradapter-not-updating-the-view/8024557#