以下内容为原创,转载请注明:http://www.cnblogs.com/tiantianbyconan/p/3364728.html

我前两天写过一篇博客《Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信》(http://www.cnblogs.com/tiantianbyconan/p/3360938.html),实现了Tab切换时保留当前Fragment状态,并在切换前自动回调onPause()方法,在切换后自动调用onResume(),这样就做到了跟TahHost一样的功能。

今天来实现下ViewPager的功能,google提供了一个FragmentPagerAdapter这么一个适配器,蛋疼的是,碰到了跟上次类似的问题。比如ViewPager有5个page,刚打开的时候,会加载page1和page2,我们手动切换到page2的时候,会加载page3,切换到page3的时候,加载page4的同时会destory掉page1,所以,还是面临同样的问题,page的状态无法保存,于是,咱还是自己来实现下好了,自己动手,丰衣足食嘛!(同样有朋友知道解决办法的话,希望联系我,赐教下哈

先来看下整个demo的结构,跟上次实现TabHost的例子差不多:

TabAFm到TabEFm都是Fragment,并且每个Fragment对应一个布局文件。

TabAFm.java:

 1 package com.wangjie.fragmentviewpagertest; 2  3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.support.v4.app.Fragment; 6 import android.view.LayoutInflater; 7 import android.view.View; 8 import android.view.ViewGroup; 9 10 /**11  * Created with IntelliJ IDEA.12  * Author: wangjie  email:tiantian.china.2@gmail.com13  * Date: 13-6-1414  * Time: 下午2:3915  */16 public class TabAFm extends Fragment{17     @Override18     public void onAttach(Activity activity) {19         super.onAttach(activity);20         System.out.println("AAAAAAAAAA____onAttach");21     }22 23     @Override24     public void onCreate(Bundle savedInstanceState) {25         super.onCreate(savedInstanceState);26         System.out.println("AAAAAAAAAA____onCreate");27     }28 29     @Override30     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {31         System.out.println("AAAAAAAAAA____onCreateView");32         return inflater.inflate(R.layout.tab_a, container, false);33     }34 35     @Override36     public void onActivityCreated(Bundle savedInstanceState) {37         super.onActivityCreated(savedInstanceState);38         System.out.println("AAAAAAAAAA____onActivityCreated");39     }40 41     @Override42     public void onStart() {43         super.onStart();44         System.out.println("AAAAAAAAAA____onStart");45     }46 47     @Override48     public void onResume() {49         super.onResume();50         System.out.println("AAAAAAAAAA____onResume");51     }52 53     @Override54     public void onPause() {55         super.onPause();56         System.out.println("AAAAAAAAAA____onPause");57     }58 59     @Override60     public void onStop() {61         super.onStop();62         System.out.println("AAAAAAAAAA____onStop");63     }64 65     @Override66     public void onDestroyView() {67         super.onDestroyView();68         System.out.println("AAAAAAAAAA____onDestroyView");69     }70 71     @Override72     public void onDestroy() {73         super.onDestroy();74         System.out.println("AAAAAAAAAA____onDestroy");75     }76 77     @Override78     public void onDetach() {79         super.onDetach();80         System.out.println("AAAAAAAAAA____onDetach");81     }82 }
View Code

如上述代码所示,TabAFm是一个Fragment,对应的布局文件是tab_a.xml,并实现了他的所有的生命周期回调函数并打印,便于调试

tab_a.xml布局中有个EditText

其他的Fragment大同小异,这里就不贴出代码了

现在来看MainActivity:

 1 package com.wangjie.fragmentviewpagertest; 2  3 import android.os.Bundle; 4 import android.support.v4.app.Fragment; 5 import android.support.v4.app.FragmentActivity; 6 import android.support.v4.view.ViewPager; 7  8 import java.util.ArrayList; 9 import java.util.List;10 11 public class MainActivity extends FragmentActivity {12     private ViewPager viewPager;13     public List<Fragment> fragments = new ArrayList<Fragment>();14     public String hello = "hello ";15 16     @Override17     public void onCreate(Bundle savedInstanceState) {18         super.onCreate(savedInstanceState);19         setContentView(R.layout.main);20 21         fragments.add(new TabAFm());22         fragments.add(new TabBFm());23         fragments.add(new TabCFm());24         fragments.add(new TabDFm());25         fragments.add(new TabEFm());26 27         viewPager = (ViewPager) findViewById(R.id.viewPager);28         FragmentViewPagerAdapter adapter = new FragmentViewPagerAdapter(this.getSupportFragmentManager(), viewPager,fragments);29         adapter.setOnExtraPageChangeListener(new FragmentViewPagerAdapter.OnExtraPageChangeListener(){30             @Override31             public void onExtraPageSelected(int i) {32                 System.out.println("Extra...i: " + i);33             }34         });35 36     }37 38 }
View Code

MainActivity上述代码所示

MainActivity是包含Fragment的Activity(也就是这里的5个Fragment)

他继承了FragmentActivity(因为我这里用的是android-support-v4.jar)

用一个List<Fragment>去维护5个Fragment,也就是5个page。

MainActivity的布局很简单,就一个ViewPager,main.xml如下:

 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3               android:orientation="vertical" 4               android:layout_width="fill_parent" 5               android:layout_height="fill_parent" 6         > 7     <android.support.v4.view.ViewPager 8         android:id="@+id/viewPager" 9         android:layout_width="match_parent"10         android:layout_height="match_parent"11         />12 13 </LinearLayout>
View Code

现在回到MainActivity中,下面这个FragmentViewPagerAdapter类是关键,是我自己编写的用于绑定和处理fragments和ViewPager之间的逻辑关系

FragmentViewPagerAdapter adapter = new FragmentViewPagerAdapter(this.getSupportFragmentManager(), viewPager,fragments);

现在看下FragmentViewPagerAdapter:

  1 package com.wangjie.fragmentviewpagertest;  2   3 import android.support.v4.app.Fragment;  4 import android.support.v4.app.FragmentManager;  5 import android.support.v4.app.FragmentTransaction;  6 import android.support.v4.view.PagerAdapter;  7 import android.support.v4.view.ViewPager;  8 import android.view.View;  9 import android.view.ViewGroup; 10  11 import java.util.List; 12  13 /** 14  * 为ViewPager添加布局(Fragment),绑定和处理fragments和viewpager之间的逻辑关系 15  * 16  * Created with IntelliJ IDEA. 17  * Author: wangjie  email:tiantian.china.2@gmail.com 18  * Date: 13-10-11 19  * Time: 下午3:03 20  */ 21 public class FragmentViewPagerAdapter extends PagerAdapter implements ViewPager.OnPageChangeListener{ 22     private List<Fragment> fragments; // 每个Fragment对应一个Page 23     private FragmentManager fragmentManager; 24     private ViewPager viewPager; // viewPager对象 25     private int currentPageIndex = 0; // 当前page索引(切换之前) 26  27     private OnExtraPageChangeListener onExtraPageChangeListener; // ViewPager切换页面时的额外功能添加接口 28  29     public FragmentViewPagerAdapter(FragmentManager fragmentManager, ViewPager viewPager , List<Fragment> fragments) { 30         this.fragments = fragments; 31         this.fragmentManager = fragmentManager; 32         this.viewPager = viewPager; 33         this.viewPager.setAdapter(this); 34         this.viewPager.setOnPageChangeListener(this); 35     } 36  37     @Override 38     public int getCount() { 39         return fragments.size(); 40     } 41  42     @Override 43     public boolean isViewFromObject(View view, Object o) { 44         return view == o; 45     } 46  47     @Override 48     public void destroyItem(ViewGroup container, int position, Object object) { 49         container.removeView(fragments.get(position).getView()); // 移出viewpager两边之外的page布局 50     } 51  52     @Override 53     public Object instantiateItem(ViewGroup container, int position) { 54         Fragment fragment = fragments.get(position); 55         if(!fragment.isAdded()){ // 如果fragment还没有added 56             FragmentTransaction ft = fragmentManager.beginTransaction(); 57             ft.add(fragment, fragment.getClass().getSimpleName()); 58             ft.commit(); 59             /** 60              * 在用FragmentTransaction.commit()方法提交FragmentTransaction对象后 61              * 会在进程的主线程中,用异步的方式来执行。 62              * 如果想要立即执行这个等待中的操作,就要调用这个方法(只能在主线程中调用)。 63              * 要注意的是,所有的回调和相关的行为都会在这个调用中被执行完成,因此要仔细确认这个方法的调用位置。 64              */ 65             fragmentManager.executePendingTransactions(); 66         } 67  68         if(fragment.getView().getParent() == null){ 69             container.addView(fragment.getView()); // 为viewpager增加布局 70         } 71  72         return fragment.getView(); 73     } 74  75     /** 76      * 当前page索引(切换之前) 77      * @return 78      */ 79     public int getCurrentPageIndex() { 80         return currentPageIndex; 81     } 82  83     public OnExtraPageChangeListener getOnExtraPageChangeListener() { 84         return onExtraPageChangeListener; 85     } 86  87     /** 88      * 设置页面切换额外功能监听器 89      * @param onExtraPageChangeListener 90      */ 91     public void setOnExtraPageChangeListener(OnExtraPageChangeListener onExtraPageChangeListener) { 92         this.onExtraPageChangeListener = onExtraPageChangeListener; 93     } 94  95     @Override 96     public void onPageScrolled(int i, float v, int i2) { 97         if(null != onExtraPageChangeListener){ // 如果设置了额外功能接口 98             onExtraPageChangeListener.onExtraPageScrolled(i, v, i2); 99         }100     }101 102     @Override103     public void onPageSelected(int i) {104         fragments.get(currentPageIndex).onPause(); // 调用切换前Fargment的onPause()105 //        fragments.get(currentPageIndex).onStop(); // 调用切换前Fargment的onStop()106         if(fragments.get(i).isAdded()){107 //            fragments.get(i).onStart(); // 调用切换后Fargment的onStart()108             fragments.get(i).onResume(); // 调用切换后Fargment的onResume()109         }110         currentPageIndex = i;111 112         if(null != onExtraPageChangeListener){ // 如果设置了额外功能接口113             onExtraPageChangeListener.onExtraPageSelected(i);114         }115 116     }117 118     @Override119     public void onPageScrollStateChanged(int i) {120         if(null != onExtraPageChangeListener){ // 如果设置了额外功能接口121             onExtraPageChangeListener.onExtraPageScrollStateChanged(i);122         }123     }124 125 126     /**127      * page切换额外功能接口128      */129     static class OnExtraPageChangeListener{130         public void onExtraPageScrolled(int i, float v, int i2){}131         public void onExtraPageSelected(int i){}132         public void onExtraPageScrollStateChanged(int i){}133     }134 135 136 }
View Code

这里解决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实现了ViewPager的功能了,同样,下面来看下各个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中:

 1 @Override 2     public void onActivityCreated(Bundle savedInstanceState) { 3         super.onActivityCreated(savedInstanceState); 4         System.out.println("BBBBBBBBBBB____onActivityCreated"); 5         this.getView().findViewById(R.id.clickme).setOnClickListener(new View.OnClickListener() { 6             @Override 7             public void onClick(View view) { 8                 // 获得绑定的FragmentActivity 9                 MainActivity activity = ((MainActivity)getActivity());10                 // 获得TabAFm的控件11                 EditText editText = (EditText) activity.fragments.get(0).getView().findViewById(R.id.edit);12 13                 Toast.makeText(activity, activity.hello + editText.getText(), Toast.LENGTH_SHORT).show();14             }15         });16     }
View Code

最终效果图:

demo下载:http://pan.baidu.com/s/1stGQ7

更多相关文章

  1. SecureRandom漏洞解析
  2. Android(安卓)3.2 以上转屏,切换屏幕,横竖屏(onConfigurationChange
  3. Android学习笔记50:使用WebView控件浏览网页
  4. 《Android(安卓)Fragment 非常详细的一篇》
  5. Android(安卓)Activity之间切换的各种效果
  6. android 禁止编辑框可编辑,使其自动调用搜狗输入法
  7. Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不
  8. Android换肤功能实现(白天、黑夜)
  9. Android项目复盘3

随机推荐

  1. linux 安装Nginx PHP
  2. 初次安装windows系统后桌面只有回收站,如
  3. LVS 负载均衡服务器搭建
  4. Git 删除 .gitignore 生成之前上传的文件
  5. 2021-02-16:n皇后问题。给定一个整数n,返
  6. 2.34 在ESXi主机添加iSCSI存储适配器
  7. 我的第九个代码
  8. 第4章 0128-史上最全的函数讲解,学习心得
  9. 洛伦兹曲线(Lorenz curve)提升指数、提升表
  10. 操作系统——计算机硬件简介