Android使用Fragment來實現ViewPager的功能(解決切換Fragment狀態不保存)以及各個Fragment之間的通信


以下內容為原創,轉載請注明: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.com
13  * Date: 13-6-14
14  * Time: 下午2:39
15  */
16 public class TabAFm extends Fragment{
17     @Override
18     public void onAttach(Activity activity) {
19         super.onAttach(activity);
20         System.out.println("AAAAAAAAAA____onAttach");
21     }
22 
23     @Override
24     public void onCreate(Bundle savedInstanceState) {
25         super.onCreate(savedInstanceState);
26         System.out.println("AAAAAAAAAA____onCreate");
27     }
28 
29     @Override
30     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     @Override
36     public void onActivityCreated(Bundle savedInstanceState) {
37         super.onActivityCreated(savedInstanceState);
38         System.out.println("AAAAAAAAAA____onActivityCreated");
39     }
40 
41     @Override
42     public void onStart() {
43         super.onStart();
44         System.out.println("AAAAAAAAAA____onStart");
45     }
46 
47     @Override
48     public void onResume() {
49         super.onResume();
50         System.out.println("AAAAAAAAAA____onResume");
51     }
52 
53     @Override
54     public void onPause() {
55         super.onPause();
56         System.out.println("AAAAAAAAAA____onPause");
57     }
58 
59     @Override
60     public void onStop() {
61         super.onStop();
62         System.out.println("AAAAAAAAAA____onStop");
63     }
64 
65     @Override
66     public void onDestroyView() {
67         super.onDestroyView();
68         System.out.println("AAAAAAAAAA____onDestroyView");
69     }
70 
71     @Override
72     public void onDestroy() {
73         super.onDestroy();
74         System.out.println("AAAAAAAAAA____onDestroy");
75     }
76 
77     @Override
78     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     @Override
17     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             @Override
31             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     @Override
103     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     @Override
119     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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM