現在很多瀏覽類型app都是viewpager + fragment + 自定義tab的組合,比如網易新聞,優酷等。
使用這種組合的好處: 可以在一個Activity中處理多個頁面,方便用戶操作,視圖結構清晰。
一、 viewpager 對應的幾個adapter
FragmentStatePagerAdapter: 爲PageAdapter子類,適用於處理很多頁,數據動態性較大,佔用內存較多的Fragment爲頁面。 特點,當不可見時,整個Fragment都會銷燬,調用onDestroy 和 onDestroyView; 數據需重新加載
一般PageAdapter中4個方法:
1. public int getCount(): 返回當前有效視圖的個數。
2. public boolean isViewFromObject(View view, Object object): 該函數用來判斷instantiateItem(ViewGroup, int)函數所返回來的Key與一個頁面視圖是否是代表的同一個視圖(即它倆是否是對應的,對應的表示同一個View)
3. public Object instantiateItem(ViewGroup container, int position): 這個函數的實現的功能是創建指定位置的頁面視圖。返回值:返回一個代表新增視圖頁面的Object(Key),這裏沒必要非要返回視圖本身,也可以這個頁面的其它容器。
4. public void destroyItem(ViewGroup container, int position, Object object): 該方法實現的功能是移除一個給定位置的頁面。適配器有責任從容器中刪除這個視圖。這是爲了確保在finishUpdate(viewGroup)返回時視圖能夠被移除。
5. public CharSequence getPageTitle(int position): 使用系統PagerTabStrip PagerTitleStrip 返回的tab字符串
二、ViewPager 滑動頁面的監聽,一般可用於對自定義tab進行動畫處理
//viewPager.setOnPageChangeListener(myOnPageChangeListener); 被棄用。 下面區別是將listener放入集合中
viewPager.addOnPageChangeListener(myOnPageChangeListener);
private MyOnPageChangeListener myOnPageChangeListener = new MyOnPageChangeListener();
public class MyOnPageChangeListener implements ViewPager.OnPageChangeListener {
@Override //滑動的過程調用 位置 當前頁面屏幕的百分比 當前頁面偏移的像素位置
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
Log.d("stormxz", "onPageScrolled 111");
}
@Override //當前頁面的位置
public void onPageSelected(int position) {
Log.d("stormxz", "onPageScrolled 222");
}
@Override //狀態 1開始 2正在滑動 0結束
public void onPageScrollStateChanged(int state) {
Log.d("stormxz", "onPageScrollStateChanged 333");
}
}
一般用來對自定義tabbar 進行位置,動畫設置
三、3種adapter使用Fragment + viewPager
1. PagerAdapter
package com.example.stormxz.viewpagerdemo;
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.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
/**
* Created by stormxz on 2017/9/6.
*/
public class MyViewPagerAdapter extends PagerAdapter {
private ArrayList<Fragment> fragments = new ArrayList<Fragment>();
private ArrayList<String> titles = new ArrayList<String>();
private FragmentManager fragmentManager = null;
public MyViewPagerAdapter(ArrayList<Fragment> viewArrayList, ArrayList<String> titlesList, FragmentManager fragmentManager) {
this.fragments = viewArrayList;
this.titles = titlesList;
this.fragmentManager = fragmentManager;
}
@Override
public int getCount() { //返回fragment 的個數
return fragments.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object; //判讀當前View是否一致
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = fragments.get(position);
if (fragment != null) {
if (!fragment.isAdded()){ //判讀當前fragment是否已經提交 ,如果沒有,則創建事務,進行提交
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(fragment, fragment.getClass().getSimpleName());
fragmentTransaction.commitAllowingStateLoss();
/**
* 在用FragmentTransaction.commit()方法提交FragmentTransaction對象後 會在進程的主線程中,用異步的方式來執行。
* 如果想要立即執行這個等待中的操作,就要調用這個方法(只能在主線程中調用)。 要注意的是,所有的回調和相關的行爲都會在這個調用中被執行完成,因此要仔細確認這個方法的調用位置。
*/
fragmentManager.executePendingTransactions();
}
if (fragment.getView() != null) {
container.addView(fragment.getView());
}
}
return fragment.getView();
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(fragments.get(position).getView()); //removeView
}
@Override
public CharSequence getPageTitle(int position) {
return titles.get(position); //返回tab 文字信息
}
}
MainActivity.java 傳遞FragmentManager tabname Fragment集合
myViewPagerAdapter = new MyViewPagerAdapter(fragments, titles, getSupportFragmentManager());
viewPager.setAdapter(myViewPagerAdapter);
一般不建議使用PagerAdapter. 建議使用其子類FragmentPagerAdapter 以及 FragmentStatePagerAdapter
2. FragmentPagerAdapter 與 FragmentStatePagerAdapter
只需要重新2個方法即可package com.example.stormxz.viewpagerdemo;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentStatePagerAdapter;
import java.util.ArrayList;
/**
* Created by stormxz on 2017/9/11.
*/
public class MyFragmentAdapter extends FragmentPagerAdapter {
private ArrayList<Fragment> fragments = new ArrayList<Fragment>();
public MyFragmentAdapter(FragmentManager fm, ArrayList<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
}
myFragmentAdapter = new MyFragmentAdapter(getSupportFragmentManager(), fragments);
viewPager.setAdapter(myFragmentAdapter);
@Override
public Object instantiateItem(ViewGroup container, int position) {
// If we already have this item instantiated, there is nothing
// to do. This can happen when we are restoring the entire pager
// from its saved state, where the fragment manager has already
// taken care of restoring the fragments we previously had instantiated.
if (mFragments.size() > position) {
Fragment f = mFragments.get(position);
if (f != null) {
return f;
}
}
if (mCurTransaction == null) { //獲得事務
mCurTransaction = mFragmentManager.beginTransaction();
}
Fragment fragment = getItem(position);
if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
if (mSavedState.size() > position) {
Fragment.SavedState fss = mSavedState.get(position);
if (fss != null) {
fragment.setInitialSavedState(fss);
}
}
while (mFragments.size() <= position) {
mFragments.add(null);
}
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false); //設置爲不可見
mFragments.set(position, fragment);
mCurTransaction.add(container.getId(), fragment); //添加Fragment
return fragment;
}
事務提交
@Override
public void finishUpdate(ViewGroup container) {
if (mCurTransaction != null) {
mCurTransaction.commitNowAllowingStateLoss();
mCurTransaction = null;
}
}
判斷fragment是否是當前的,是則設置爲用戶可見
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment)object;
if (fragment != mCurrentPrimaryItem) {
if (mCurrentPrimaryItem != null) {
mCurrentPrimaryItem.setMenuVisibility(false);
mCurrentPrimaryItem.setUserVisibleHint(false);
}
if (fragment != null) {
fragment.setMenuVisibility(true);
fragment.setUserVisibleHint(true);
}
mCurrentPrimaryItem = fragment;
}
}
四、 系統PagerTabStrip PagerTitleStrip
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="368dp"
android:layout_height="495dp"
tools:layout_editor_absoluteY="8dp"
tools:layout_editor_absoluteX="8dp">
<android.support.v4.view.PagerTabStrip
android:id="@+id/pager_tab_strip"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</android.support.v4.view.PagerTabStrip>
<!-- <android.support.v4.view.PagerTitleStrip
android:id="@+id/pager_title_strip"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</android.support.v4.view.PagerTitleStrip>-->
</android.support.v4.view.ViewPager>
2. 在Adapter中傳入tabname集合,並在不同位置進行提取
@Override
public CharSequence getPageTitle(int position) {
return titles.get(position);
}
相同點:
(1)作爲ViewPager內部控件進行使用,只需要重寫adapter中的getPageTitle(return position的字符串)
(2) android:layout_gravity 屬性設置爲TOP或BOTTOM來將它顯示在ViewPager的頂部或底部。
不同點: PagerTabStrip 支持點擊tab進行跳轉頁面,有下劃線; PagerTitleStrip 則無
主流app 不會用