Android -- ViewPager、Fragment、状态保存、通信
工程架构
TabAFm到TabEFm都是Fragment,并且每个Fragment对应一个布局文件。
TabAFm.java
package com.yydcdut.viewpagerstudy; import android.app.Activity; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class TabAFm extends Fragment { @Override public void onAttach(Activity activity) { super.onAttach(activity); System.out.println("AAAAAAAAAA____onAttach"); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); System.out.println("AAAAAAAAAA____onCreate"); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { System.out.println("AAAAAAAAAA____onCreateView"); return inflater.inflate(R.layout.tab_a, container, false); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); System.out.println("AAAAAAAAAA____onActivityCreated"); } @Override public void onStart() { super.onStart(); System.out.println("AAAAAAAAAA____onStart"); } @Override public void onResume() { super.onResume(); System.out.println("AAAAAAAAAA____onResume"); } @Override public void onPause() { super.onPause(); System.out.println("AAAAAAAAAA____onPause"); } @Override public void onStop() { super.onStop(); System.out.println("AAAAAAAAAA____onStop"); } @Override public void onDestroyView() { super.onDestroyView(); System.out.println("AAAAAAAAAA____onDestroyView"); } @Override public void onDestroy() { super.onDestroy(); System.out.println("AAAAAAAAAA____onDestroy"); } @Override public void onDetach() { super.onDetach(); System.out.println("AAAAAAAAAA____onDetach"); } }
如上述代码所示,TabAFm是一个Fragment,对应的布局文件是tab_a.xml,并实现了他的所有的生命周期回调函数并打印,便于调试。tab_a.xml布局中有个EditText,其他的Fragment大同小异,这里就不贴出代码了
MainActivity
package com.yydcdut.viewpagerstudy; import java.util.ArrayList; import java.util.List; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.view.ViewPager; public class MainActivity extends FragmentActivity { private ViewPager viewPager; public List<Fragment> fragments = new ArrayList<Fragment>(); public String hello = "hello "; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); fragments.add(new TabAFm()); fragments.add(new TabBFm()); fragments.add(new TabCFm()); fragments.add(new TabDFm()); fragments.add(new TabEFm()); viewPager = (ViewPager) findViewById(R.id.viewPager); FragmentViewPagerAdapter2 adapter = new FragmentViewPagerAdapter2(this.getSupportFragmentManager(), viewPager,fragments); adapter.setOnExtraPageChangeListener(new FragmentViewPagerAdapter2.OnExtraPageChangeListener(){ @Override public void onExtraPageSelected(int i) { System.out.println("Extra...i: " + i); } @Override public void onExtraPageScrolled(int i, float v, int i2) { super.onExtraPageScrolled(i, v, i2); } @Override public void onExtraPageScrollStateChanged(int i) { super.onExtraPageScrollStateChanged(i); } }); } }
MainActivity上述代码所示
MainActivity是包含Fragment的Activity(也就是这里的5个Fragment)
他继承了FragmentActivity(因为我这里用的是android-support-v4.jar)
用一个List<Fragment>去维护5个Fragment,也就是5个page。
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
现在回到MainActivity中,下面这个FragmentViewPagerAdapter类是关键,是我自己编写的用于绑定和处理fragments和ViewPager之间的逻辑关系
FragmentViewPagerAdapter2 adapter = new FragmentViewPagerAdapter2(this.getSupportFragmentManager(), viewPager,fragments);
FragmentViewPagerAdapter2
package com.yydcdut.viewpagerstudy; import java.util.List; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.view.View; import android.view.ViewGroup; public class FragmentViewPagerAdapter2 { private List<Fragment> fragments; // 每个Fragment对应一个Page private FragmentManager fragmentManager; private ViewPager viewPager; // viewPager对象 private int currentPageIndex = 0; // 当前page索引(切换之前) private OnExtraPageChangeListener onExtraPageChangeListener; // ViewPager切换页面时的额外功能添加接口 /** * 构造函数 * * @param fragmentManager * @param viewPager * @param fragments */ public FragmentViewPagerAdapter2(FragmentManager fragmentManager, ViewPager viewPager, List<Fragment> fragments) { this.fragments = fragments; this.fragmentManager = fragmentManager; this.viewPager = viewPager; // PagerAdapter MyPagerAdapter myPagerAdapter = new MyPagerAdapter(); this.viewPager.setAdapter(myPagerAdapter); // PageChangeListener MyPageChangeListener myPageChangeListener = new MyPageChangeListener(); this.viewPager.setOnPageChangeListener(myPageChangeListener); } /** * 当前page索引(切换之前) * * @return */ public int getCurrentPageIndex() { return currentPageIndex; } /** * PagerAdapter 要使用PagerAdapter,首先要继承PagerAdapter类,然后至少覆盖以下方法 * instantiateItem(ViewGroup, * int)【这个方法,return一个对象,这个对象表明了PagerAdapter适配器选择哪个对象放在当前的ViewPager中】 * destroyItem(ViewGroup, int, Object)【这个方法,是从ViewGroup中移出当前View】 * getCount()【这个方法,是获取当前窗体界面数】 isViewFromObject(View, Object) * 【这个方法,在帮助文档中原文是could be implemented as return view == * object,也就是用于判断是否由对象生成界面】 * * @author sansung * */ class MyPagerAdapter extends PagerAdapter { @Override public Object instantiateItem(ViewGroup container, int position) { Fragment fragment = fragments.get(position);// 取得位置,获取出来Fragment if (!fragment.isAdded()) { // 如果fragment还没有added FragmentTransaction ft = fragmentManager.beginTransaction(); ft.add(fragment, fragment.getClass().getSimpleName()); ft.commit(); /** * 在用FragmentTransaction.commit()方法提交FragmentTransaction对象后 * 会在进程的主线程中,用异步的方式来执行。 如果想要立即执行这个等待中的操作,就要调用这个方法(只能在主线程中调用)。 * 要注意的是,所有的回调和相关的行为都会在这个调用中被执行完成,因此要仔细确认这个方法的调用位置。 */ fragmentManager.executePendingTransactions(); } if (fragment.getView().getParent() == null) { container.addView(fragment.getView()); // 为viewpager增加布局 } return fragment.getView(); } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(fragments.get(position).getView()); // 移出viewpager两边之外的page布局 } @Override public int getCount() { return fragments.size(); } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } } /** * OnPageChangeListener * * @author sansung * */ class MyPageChangeListener implements OnPageChangeListener { /** * 此方法是在状态改变的时候调用,其中arg0这个参数有三种状态(0,1,2)。 arg0 * ==1的时辰默示正在滑动,arg0==2的时辰默示滑动完毕了,arg0==0的时辰默示什么都没做。 */ @Override public void onPageScrollStateChanged(int arg0) { if (null != onExtraPageChangeListener) { // 如果设置了额外功能接口 onExtraPageChangeListener.onExtraPageScrollStateChanged(arg0); } } /** * 当页面在滑动的时候会调用此方法,在滑动被停止之前,此方法回一直得到调用。 其中三个参数的含义分别为: arg0 * :当前页面,及你点击滑动的页面 arg1:当前页面偏移的百分比 arg2:当前页面偏移的像素位置 */ @Override public void onPageScrolled(int arg0, float arg1, int arg2) { if (null != onExtraPageChangeListener) { // 如果设置了额外功能接口 onExtraPageChangeListener.onExtraPageScrolled(arg0, arg1, arg2); } } /** * 此方法是页面跳转完后得到调用,arg0是你当前选中的页面的Position(位置编号)。 */ @Override public void onPageSelected(int arg0) { fragments.get(currentPageIndex).onPause(); // 调用切换前Fargment的onPause() // fragments.get(currentPageIndex).onStop(); // // 调用切换前Fargment的onStop() if (fragments.get(arg0).isAdded()) { // fragments.get(i).onStart(); // 调用切换后Fargment的onStart() fragments.get(arg0).onResume(); // 调用切换后Fargment的onResume() } currentPageIndex = arg0; if (null != onExtraPageChangeListener) { // 如果设置了额外功能接口 onExtraPageChangeListener.onExtraPageSelected(arg0); } } } /** * page切换额外功能接口 */ static class OnExtraPageChangeListener { public void onExtraPageScrolled(int i, float v, int i2) { } public void onExtraPageSelected(int i) { } public void onExtraPageScrollStateChanged(int i) { } } /** * 得到页面切换额外功能监听器 * * @return onExtraPageChangeListener */ public OnExtraPageChangeListener getOnExtraPageChangeListener() { return onExtraPageChangeListener; } /** * 设置页面切换额外功能监听器 * * @param onExtraPageChangeListener */ public void setOnExtraPageChangeListener( OnExtraPageChangeListener onExtraPageChangeListener) { this.onExtraPageChangeListener = onExtraPageChangeListener; } }
这里解决Fragment切换重新加载布局的办法,用的是把几个Fragment全部Add,然后根据要显示的哪个Fragment就把哪个Fragment的View给添加到“ViewGroup container”上去。
// 以下打开程序后,加载PageA和PageB 10-12 09:42:46.671: INFO/System.out(27248): AAAAAAAAAA____onAttach 10-12 09:42:46.671: INFO/System.out(27248): AAAAAAAAAA____onCreate 10-12 09:42:46.671: INFO/System.out(27248): AAAAAAAAAA____onCreateView 10-12 09:42:46.761: INFO/System.out(27248): AAAAAAAAAA____onActivityCreated 10-12 09:42:46.765: INFO/System.out(27248): AAAAAAAAAA____onStart 10-12 09:42:46.765: INFO/System.out(27248): AAAAAAAAAA____onResume 10-12 09:42:46.847: INFO/System.out(27248): BBBBBBBBBBB____onAttach 10-12 09:42:46.847: INFO/System.out(27248): BBBBBBBBBBB____onCreate 10-12 09:42:46.851: INFO/System.out(27248): BBBBBBBBBBB____onCreateView 10-12 09:42:46.867: INFO/System.out(27248): BBBBBBBBBBB____onActivityCreated 10-12 09:42:46.867: INFO/System.out(27248): BBBBBBBBBBB____onStart 10-12 09:42:46.867: INFO/System.out(27248): BBBBBBBBBBB____onResume // 以下切换到PageB 10-12 09:42:57.285: INFO/System.out(27248): AAAAAAAAAA____onPause // 切换到PageB前会调用PageA的onPause()方法 10-12 09:42:57.285: INFO/System.out(27248): BBBBBBBBBBB____onResume // 切换到PageB后会调用PageB的onResume()方法 10-12 09:42:57.285: INFO/System.out(27248): Extra...i: 1 // 切换页面时会调用切换额外功能接口(用户可以自己写需要的逻辑) 10-12 09:42:57.582: INFO/System.out(27248): CCCCCCCCCC____onAttach // 切换到PageB后会加载PageC 10-12 09:42:57.586: INFO/System.out(27248): CCCCCCCCCC____onCreate 10-12 09:42:57.586: INFO/System.out(27248): CCCCCCCCCC____onCreateView 10-12 09:42:57.675: INFO/System.out(27248): CCCCCCCCCC____onActivityCreated 10-12 09:42:57.675: INFO/System.out(27248): CCCCCCCCCC____onStart 10-12 09:42:57.675: INFO/System.out(27248): CCCCCCCCCC____onResume // 以下切换到PageC 10-12 09:43:18.261: INFO/System.out(27248): BBBBBBBBBBB____onPause // 切换到PageC前会调用PageB的onPause()方法 10-12 09:43:18.261: INFO/System.out(27248): CCCCCCCCCC____onResume // 切换到PageC后会调用PageC的onResume()方法 10-12 09:43:18.261: INFO/System.out(27248): Extra...i: 2 // 切换页面时会调用切换额外功能接口(用户可以自己写需要的逻辑) 10-12 09:43:18.726: INFO/System.out(27248): DDDDDDDDD____onAttach // 切换到PageC后会加载PageD 10-12 09:43:18.726: INFO/System.out(27248): DDDDDDDDD____onCreate 10-12 09:43:18.726: INFO/System.out(27248): DDDDDDDDD____onCreateView 10-12 09:43:18.738: INFO/System.out(27248): DDDDDDDDD____onActivityCreated 10-12 09:43:18.738: INFO/System.out(27248): DDDDDDDDD____onStart 10-12 09:43:18.742: INFO/System.out(27248): DDDDDDDDD____onResume // 以下切换到PageB 10-12 09:43:20.742: INFO/System.out(27248): CCCCCCCCCC____onPause // 切换到PageB前会调用PageC的onPause()方法 10-12 09:43:20.742: INFO/System.out(27248): BBBBBBBBBBB____onResume // 切换到PageB后会调用PageB的onResume()方法 10-12 09:43:20.746: INFO/System.out(27248): Extra...i: 1 // 切换页面时会调用切换额外功能接口(用户可以自己写需要的逻辑)
Fragment之间的通信
现在的情况是TabAFm中有个EditText,TabBFm中有个Button,MainActivity中有个变量“hello”
要做的是,切换到A,输入“I'm PageA”,切换到B,点击Button后,Toast显示“hello I'm PageA”
MainActivity中没什么好说的,就一个hello变量:
public String hello = "hello ";
TabBFm.java:
@Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); System.out.println("BBBBBBBBBB____onActivityCreated"); this.getView().findViewById(R.id.clickme).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 获得绑定的FragmentActivity MainActivity activity = ((MainActivity)getActivity()); // 获得TabAFm的控件 EditText editText = (EditText) activity.fragments.get(0).getView().findViewById(R.id.edit); Toast.makeText(activity, activity.hello + editText.getText(), Toast.LENGTH_SHORT).show(); } }); }
PagerAdapter
PageAdapter是一个抽象类,直接继承于Object,导入包android.support.v4.view.PagerAdapter即可使用。
关于PageAapter的描述,原文是这样的:Base class providing the adapter to populate pages inside of a ViewPager. You will most likely want to use a more specific implementation of this, such as FragmentPagerAdapter or FragmentStatePagerAdapter。
其实PagerAdapter就是ViewPager提供的一个适配器,方便我们对各个View进行控制。那ViewPager又是什么呢?它是实现左右两个屏幕平滑地切换的一个类,具体的自己百度google…关于ViewPager的用法好多。
要使用PagerAdapter,首先要继承PagerAdapter类,然后至少覆盖以下方法
/**这个方法,return一个对象,这个对象表明了PagerAdapter适配器选择哪个对象 *放在当前的ViewPager中 **/ instantiateItem(ViewGroup, int)
/**这个方法,是从ViewGroup中移出当前View**/ destroyItem(ViewGroup, int, Object)
/**这个方法,是获取当前窗体界面数**/ getCount()
/**这个方法,在帮助文档中原文是could be implemented as return view == object, *也就是用于判断是否由对象生成界面 **/ isViewFromObject(View, Object)
ViewPager onPageChangeListener
OnPageChangeListener这个接口需要实现三个方法:(onPageScrollStateChanged,onPageScrolled ,onPageSelected)
onPageScrollStateChanged(int arg0)
此方法是在状态改变的时候调用,其中arg0这个参数有三种状态(0,1,2)。
arg0 ==1的时辰默示正在滑动,arg0==2的时辰默示滑动完毕了,arg0==0的时辰默示什么都没做。
onPageScrolled(int arg0,float arg1,int arg2)
当页面在滑动的时候会调用此方法,在滑动被停止之前,此方法回一直得到调用。其中三个参数的含义分别为:
arg0 :当前页面,及你点击滑动的页面
arg1:当前页面偏移的百分比
arg2:当前页面偏移的像素位置
onPageSelected(int arg0)
此方法是页面跳转完后得到调用,arg0是你当前选中的页面的Position(位置编号)。
我是天王盖地虎的分割线
源代码:http://pan.baidu.com/s/1dD1Qx01
viewpager学习.zip
参考:http://www.cnblogs.com/tiantianbyconan/p/3364728.html
出处:http://yydcdut.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。