如下內容爲原創,轉載請註明:http://www.cnblogs.com/tiantianbyconan/p/3364728.html
html
我前兩天寫過一篇博客《Android使用Fragment來實現TabHost的功能(解決切換Fragment狀態不保存)以及各個Fragment之間的通訊》(http://www.cnblogs.com/tiantianbyconan/p/3360938.html),實現了Tab切換時保留當前Fragment狀態,並在切換前自動回調onPause()方法,在切換後自動調用onResume(),這樣就作到了跟TahHost同樣的功能。java
今天來實現下ViewPager的功能,google提供了一個FragmentPagerAdapter這麼一個適配器,蛋疼的是,碰到了跟上次相似的問題。好比ViewPager有5個page,剛打開的時候,會加載page1和page2,咱們手動切換到page2的時候,會加載page3,切換到page3的時候,加載page4的同時會destory掉page1,因此,仍是面臨一樣的問題,page的狀態沒法保存,因而,咱仍是本身來實現下好了,本身動手,豐衣足食嘛!(一樣 有朋友知道解決辦法的話,但願聯繫我,賜教下哈)android
先來看下整個demo的結構,跟上次實現TabHost的例子差很少:app
TabAFm到TabEFm都是Fragment,而且每一個Fragment對應一個佈局文件。異步
TabAFm.java:ide
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 }
如上述代碼所示,TabAFm是一個Fragment,對應的佈局文件是tab_a.xml,並實現了他的全部的生命週期回調函數並打印,便於調試函數
tab_a.xml佈局中有個EditText佈局
其餘的Fragment大同小異,這裏就不貼出代碼了this
如今來看MainActivity:google
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 }
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>
如今回到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 }
這裏解決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 }
最終效果圖: