Android UI學習筆記 之 使用ViewPager實現導航
ViewPager的用處就如所示(圖源網路),當我們左右滑動螢幕時,會從一個頁卡轉到下一個頁卡。
ViewPager中預設三個為一組的載入,例如,view1 view2 view3,當我們向左滑動時,view1會被銷毀,
而view4(如果有的話)就會執行個體化載入進來,變成view2 view3 view4的樣子。
使用ViewPager大致分為以下步驟:
①建立資料來源List或者List。
②將資料來源綁定到適配器,不同的資料來源有不同的適配器。
③再將適配器綁定到當前的ViewPager中,完成。
當填充的內容不同時,使用的適配器也不同。
PagerAdapter適配器對應的資料來源是List,能動態載入頁卡,銷毀頁卡。
FragmentPagerAdapter適配器對應的資料來源是List,不能動態載入頁卡,銷毀頁卡,一次性全部匯入。
FragmentStatePagerAdapter適配器對應的資料來源是List,能動態載入頁卡,銷毀頁卡。
①建立資料來源List或者List。
ViewPager中可以填充View和Fragment作為頁卡。
我們這裡以View為例,先建立一個簡單的layout,裡面只有一個TextView,用來顯示第幾個頁卡。
然後在Activity中將這個layout
轉換為View對象,有兩種方法,這裡大致提一下。
//第一種方法LayoutInflater lf = getLayoutInflater().from(this);//先擷取LayoutInflater 對象lf.inflate(resource, root);//再inflate擷取view,resource表示layout的布局檔案,root表示需要附加到resource資源檔的根控制項//第二種方法View.inflate(context, resource, root);//context表示當前的上下文,resouce和root參照上面解釋//這裡的root就是說要把layout轉換得到的view載入到哪一個ViewGroup裡面,我們這裡不需要.所以設定為null
得到的view在
添加到List集合裡面,這樣第一步建立資料來源就完成了。
viewList = new ArrayList(); for (int i = 0; i < 4; i++) { View view = View.inflate(MainActivity.this, R.layout.view, null); ((TextView) view.findViewById(R.id.pageText)).setText("這是第" + i + "個View"); viewList.add(view); }
②將資料來源綁定到適配器,不同的資料來源有不同的適配器。
我們需要自己來寫一個適配器,因為之前用的是View來填充的,所以這裡使用PagerAdapter。
public class MyViewPagerAdapter extends PagerAdapter { List viewList;//頁卡的View集合 List titleList;//頁卡的標題集合 public MyViewPagerAdapter(List viewList, List titleList) {//自訂的構造方法 this.viewList = viewList; this.titleList = titleList; } @Override public int getCount() { return viewList.size();//返回頁卡數量 } @Override public boolean isViewFromObject(View view, Object object) { return view==object;//這個view是否來自object的類型 } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(viewList.get(position));//執行個體化一個頁卡,左右滑動時調用 return viewList.get(position); } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(viewList.get(position));//銷毀一個頁卡,左右滑動時調用 } @Override public CharSequence getPageTitle(int position) { return titleList.get(position);//設定頁卡的標題,如中的FragmentA,FragmentB,FragmentC }}
裡面有一些常用的方法要重寫。
getCount()返回的是頁卡的數量,也就是你填充進去的View的
數量,我們用集合的size()方法返回一個int。
isViewFromObject()判斷的是view的
類型,有時候我們要判斷這個view是否為TextView或者Button之類的。
instantiateItem()這個方法的用法,就是當頁面是view1 view2 view3時,向左滑動,出現view4的時候調用的,用來
載入view4,形成view2 view3 view4。
destroyItem()和上一個方法同時調用,
銷毀view1,本質上就是從ViewGroup中刪掉view1,加入view4。
getPageTitle()顯示的是
標題,如最上面圖中的fragmengA,fragmengB,fragmengC。
我們寫了個適配器之後,之後當然就是載入資料來源了。
第二步的主要工作就是寫適配器了。
myViewPagerAdapter = new MyViewPagerAdapter(viewList, titleList);//將List傳入,適配器中要寫構造方法
③再將適配器綁定到當前的ViewPager中,完成。
先在Activity的XML布局檔案中,加入ViewPager。
實現中的FragmentA,FragmentB,FragmentC的標題其實有兩種方法,
使用PagerTabStrip或者PagerTitleStrip兩種,注意只能取其中一種方法。
然後通過layout_gravity來布置,我們把tab放在頂部,title放在底部。
<android.support.v4.view.viewpager android:id="@+id/viewPager" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center"> <android.support.v4.view.pagertabstrip android:id="@+id/tab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top" android:background="@color/yellow"> </android.support.v4.view.pagertabstrip> <android.support.v4.view.pagertitlestrip android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom" android:background="@color/blue"> </android.support.v4.view.pagertitlestrip></android.support.v4.view.viewpager>
會造成tab的失效(PagerTabStrip是PagerTitleStrip的子類,有興趣的可以看下API)
然後綁定適配器,完成。
viewPager = (ViewPager) findViewById(R.id.viewPager);viewPager.setAdapter(myViewPagerAdapter);
附加:
④如果覺得樣式很醜的話,我們可以自訂樣式
建議還是實際寫一下代碼,增加印象。
//在pagerTabStrip中有以下方法pagerTabStrip.setBackgroundColor(int color);//導覽列的背景色pagerTabStrip.setTextColor(int color);//導覽列的文字色pagerTabStrip.setDrawFullUnderline(boolean drawFull);//導覽列底線是否顯示pagerTabStrip.setTabIndicatorColor(int color);//當前頁卡的選中的線的顏色
⑤如果不是用View,而是用Fragment填充呢
通過查閱API,我們可以知道FragmentPagerAdapter和FragmentStatePagerAdapter是兄弟關係,都是直接繼承自PagerAdapter。
兩者的區別在於FragmentPagerAdapter不能動態載入頁卡,是一次性匯入所有頁卡,而FragmentStatePagerAdapter是和PagerAdapter一樣動態載入頁卡的。
和View一樣,我們為FragmentPagerAdapter適配器添加資料來源List,然後重寫FragmentPagerAdapter中的方法(繼承自PagerAdapter)。
注意FragmentPagerAdapter是一次性載入所有頁卡,所以不用重寫instantiateItem()和destroyItem()(這兩個方法在FragmentStatePagerAdapter要重寫)。
值得注意的是我們需要import android.support.v4.app.Fragment;而不是import android.app.Fragment。
並且,我們的Activity要繼承自FragmentActivity,
並且在new對象的時候,要在Activity中用getSupportFragmentManager()擷取FragmentManager對象。
public MyFragmentPagerAdapter(FragmentManager fm,List fragmentList, List titleList) { super(fm); this.fragmentList = fragmentList; this.titleList = titleList; }
⑥最後,我們再添加一個監聽器
public class MainActivity extends FragmentActivity implements ViewPager.OnPageChangeListener{ @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { System.out.println("當前是第"+position+"個頁卡" + ",當前頁面位移的百分比:"+positionOffset+ ",當前頁面位移的像素位置:"+positionOffsetPixels); //當頁卡滾動時調用該方法 } @Override public void onPageSelected(int position) { Toast.makeText(MainActivity.this, "當前是第"+position+"個頁卡", Toast.LENGTH_SHORT).show(); //當頁卡改變時調用該方法 } @Override public void onPageScrollStateChanged(int state) { switch (state) { case 0: Toast.makeText(MainActivity.this, "滑動完畢", Toast.LENGTH_SHORT).show();break; case 1: Toast.makeText(MainActivity.this, "手指按下", Toast.LENGTH_SHORT).show();break; case 2: Toast.makeText(MainActivity.this, "手指抬起", Toast.LENGTH_SHORT).show();break; } //當滑動狀態改變時調用該方法 }
以下附上以View填充的ViewPager的Demo源碼。
public class MainActivity extends Activity implements ViewPager.OnPageChangeListener{ List viewList;//填充View資料來源 List titleList;//View的標題集合 MyViewPagerAdapter myViewPagerAdapter;//自訂的以View為資料來源的適配器 PagerTabStrip pagerTabStrip;//導覽列 ViewPager viewPager;//被填充的組件 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); viewList = new ArrayList(); titleList = new ArrayList(); View[] views = new View[4]; for (int i = 0; i < 4; i++) { views[i] = View.inflate(MainActivity.this, R.layout.view, null);//將view.xml轉化為View對象 ((TextView) views[i].findViewById(R.id.pageText)).setText("這是第" + i + "個View"); titleList.add("第" + i + "頁");//添加標題到集合 viewList.add(views[i]);//添加view到集合 } pagerTabStrip = (PagerTabStrip) findViewById(R.id.tab);//自訂導覽列樣式 pagerTabStrip.setBackgroundColor(Color.YELLOW);//導覽列背景色 pagerTabStrip.setTextColor(Color.BLUE);//導覽列文字色 pagerTabStrip.setDrawFullUnderline(false);//導覽列底線是否顯示 pagerTabStrip.setTabIndicatorColor(Color.RED);//導覽列選中的當前頁卡的底線顏色 myViewPagerAdapter = new MyViewPagerAdapter(viewList, titleList); viewPager = (ViewPager) findViewById(R.id.viewPager); viewPager.setAdapter(myViewPagerAdapter);//添加適配器到ViewPager viewPager.setOnPageChangeListener(this);//設定監聽器 } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { System.out.println("當前是第"+position+"個頁卡" + ",當前頁面位移的百分比:"+positionOffset+ ",當前頁面位移的像素位置:"+positionOffsetPixels); //當頁卡滾動時調用該方法 } @Override public void onPageSelected(int position) { Toast.makeText(MainActivity.this, "當前是第"+position+"個頁卡", Toast.LENGTH_SHORT).show(); //當頁卡改變時調用該方法 } @Override public void onPageScrollStateChanged(int state) { switch (state) { case 0: Toast.makeText(MainActivity.this, "滑動完畢", Toast.LENGTH_SHORT).show();break; case 1: Toast.makeText(MainActivity.this, "手指按下", Toast.LENGTH_SHORT).show();break; case 2: Toast.makeText(MainActivity.this, "手指抬起", Toast.LENGTH_SHORT).show();break; } //當滑動狀態改變時調用該方法 }}
public class MyViewPagerAdapter extends PagerAdapter { List viewList; List titleList; public MyViewPagerAdapter(List viewList, List titleList) { this.viewList = viewList; this.titleList = titleList; } @Override public int getCount() { return viewList.size();//返回頁卡數量 } @Override public boolean isViewFromObject(View view, Object object) { return view==object;//這個view是否來自object的類型 } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(viewList.get(position));//執行個體化一個頁卡 return viewList.get(position); } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(viewList.get(position));//銷毀一個頁卡 } @Override public CharSequence getPageTitle(int position) { return titleList.get(position);//設定頁卡的標題 }}