ViewPager 的用法詳解

現在很多瀏覽類型app都是viewpager + fragment + 自定義tab的組合,比如網易新聞,優酷等。

使用這種組合的好處: 可以在一個Activity中處理多個頁面,方便用戶操作,視圖結構清晰。

一、 viewpager 對應的幾個adapter

PagerAdapter: 一般適配器,圖片,view,Fragment都行。
FragmentPagerAdapter: 爲PageAdapter子類,適用於數量較少的Fragment爲頁面。特點,每一個生成的Fragment都將保存到內存中,當不可見時,銷燬Fragment的view,調用onDestroyView; 用戶體驗好
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();
    }
}

MainActivity.java 中傳遞FragmentManager  以及Fragment的集合;  給ViewPager添加適配器
    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

1. 使用,將其作爲子類View 放入ViewPager中
<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  不會用

發佈了37 篇原創文章 · 獲贊 10 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章