TabLayout-ViewPager填充Fragment和懶載入

森林森發表於2016-10-11

Tablayout+ViewPager填充Fragment和懶載入

這裡寫圖片描述

使用Fragment來填充ViewPager

TabLayout+ViewPager+Fragmenet是使用非常多的控制元件組合。

TabLayout元件的簡單介紹

  • TabLayout是Material Design元件開發中的一種,使用時需要先匯入design庫的依賴。
  • TabLayout做出的效果是一排可以滑動的Tab,相當於一排指示器。
  • 在佈局中申明控制元件
<android.support.design.widget.TabLayout
        android:id="@+id/tablayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabBackground="@color/colorPrimaryDark"
        app:tabIndicatorColor="#ff0000"
        app:tabIndicatorHeight="2dp"
        app:tabTextColor="@color/colorAccent"
        app:tabSelectedTextColor="#FFFFFF"
        app:tabMode="scrollable"
        app:tabPadding="5dp">

    </android.support.design.widget.TabLayout>
  • 基本屬性介紹,佈局和程式碼都可以使用

  • 列表內容

    • tabBackground 背景色
    • tabIndicatorColor:指示器顏色,橫線
    • tabIndicatorHeight 指示器高度
    • tabTextColor 指示器,文字 沒有選擇時正常的顏色
    • tabSelectedTextColor 指示器,文字 選擇時顏色
    • tabPadding 指示器 內邊距
    • app:tabMode=”scrollable” 模式,有scrollable和fixed兩種,分別表示可以滑動和固定的意思

  • 程式碼中繫結ViewPager

    • 在ViewPager設定Adapter之後,呼叫tabLayout的setupWithViewPager方法繫結ViewPager
    • 設定顯示的內容
    • 可以呼叫tabLayout的addTab方法新增
      -也可以重寫ViewPager介面卡的getPagerTitle方法返回顯示的內容

FragmentPagerAdapter與FragmentStatePagerAdapter的區別

FragmentPagerAdapter

  • FragmentPagerAdapter類預設會對getItem()方法返回的Fragment做快取處理,只有當第一次開啟ViewPager的頁面才會去建立Fragment的物件,後面再開啟頁面時就會直接從快取中獲取Fragment物件的引用,這樣getItem方法就不會呼叫了。

  • 因為FragmentPagerAdapter做了快取處理,所有當建立很多的Fragment時記憶體就會吃不消,應用程式有可能會崩掉,所以呢,FragmentPagerAdapter不適合做大量資料的Fragment顯示,比較適合資料不變的靜態Fragment顯示。

FragmentStatePagerAdapter

  • FragmentStatePagerAdapter正好與之相反,每次進入頁面時都會建立Fragment物件,每次滑出時都會銷燬對應的Fragment物件,沒有做一點的快取,這樣記憶體就完全的解放出來了。

  • FragmentStatePagerAdapter在銷燬Fragment時會呼叫onSaveInstanceState方法儲存一些資料資訊,然後下一次建立Fragment時會將這些資料讀取出來

ViewPager的預載入

ViewPager天生會載入左右兩側的頁面,這是通過一個叫做DEFAULT_OFFSCREEN_PAGES的屬性指定的,通過setOffscreenPageLimit(int)可以指定這個屬性的值。

 private static final int DEFAULT_OFFSCREEN_PAGES = 1;

public void setOffscreenPageLimit(int limit) {
        if (limit < DEFAULT_OFFSCREEN_PAGES) {
            Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to "
                    + DEFAULT_OFFSCREEN_PAGES);
            limit = DEFAULT_OFFSCREEN_PAGES;
        }
        if (limit != mOffscreenPageLimit) {
            mOffscreenPageLimit = limit;
            populate();
        }
    }

發現要是給的值小於1,那還是預設為1,也就是說這個方法只能指定載入更多的頁面。並不能解決問題,設定為0,還是不設定都一樣預設為1,只有大於1時才有作用

Fragment實現懶載入

Fragment的生命週期中,我們一般在onCreateView方法初始化檢視,onActivityCreated方法初始化資料

  • 通過setUserVisibleHint和getUserVisibleHint方法來設定和獲取Fragment的顯示狀態,當顯示了才去載入資料。因為每一個Fragment都是這樣,所以在BaseFragment中完成操作。
 /**
     * setUserVisibleHint是在onCreateView之前呼叫的
     *
     * @param isVisibleToUser
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {

        super.setUserVisibleHint(isVisibleToUser);

        /**
         * 判斷是否可見
         */
        if(getUserVisibleHint()) {

            isVisible = true;
            //執行可見方法-初始化資料之類
            onVisible();

        } else {

            isVisible = false;
            //不可見
            onInvisible();
        }

    }
  • onActivityCreated中也做判斷
 @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {

        super.onActivityCreated(savedInstanceState);
        //這裡 初始化view的各控制元件 資料
        isPrepared = true;
        lazyLoad();

    }
  • lazyLoad
/**
     * 可見做懶載入
     */
    private void onVisible() {
        lazyLoad();
    }

    /**
     * 懶載入
     */
    private void lazyLoad() {
        /**
         * 判斷是否可見,或者 初始化view的各控制元件
         */
        if(!isVisible || !isPrepared) {
            return;
        }
        //可見 或者 控制元件初始化完成 就 載入資料
        initData();

    }

第二種 將lazyLoad抽象方法 在子類在實現

子Fragment繼承BaseFramentTabLayout

// 標誌位,標誌已經初始化完成。
    private boolean isPrepared;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d(LOG_TAG, "onCreateView");
        View view = inflater.inflate(R.layout.fragment_open_result, container, false);
        //XXX初始化view的各控制元件
    isPrepared = true;
        lazyLoad();
        return view;
    }
    @Override
    protected void lazyLoad() {
        if(!isPrepared || !isVisible) {
            return;
        }
        //填充各控制元件的資料
    }

個人主頁
https://ln0491.github.io/
http://ln0491.coding.me/
原始碼:
https://github.com/ln0491/ViewPagerDemo

相關文章