Android開發筆記(一百七十二)第二代翻頁視圖ViewPager2

正如RecyclerView橫空出世取代ListView和GridView那樣,Android也推出了二代翻頁視圖ViewPager2,打算替換原來的翻頁視圖ViewPager。與ViewPager相比,ViewPager2支持更豐富的界面特效,包括但不限於下列幾點:
1、不但支持水平方向翻頁,還支持垂直方向翻頁;
2、支持RecyclerView.Adapter,允許調用適配器對象的notifyItem***方法,從而動態刷新某項視圖;
3、除了當前頁,也支持展示左右兩頁的部分區域;
4、支持在翻頁過程中展示自定義的切換動畫;
雖然ViewPager2增加了這麼棒的功能,但它用起來非常簡單,掌握下面幾個方法就夠了:
setAdapter:設置二代翻頁視圖的頁面適配器。
setOrientation:設置二代翻頁視圖的翻頁方向。其中ViewPager2.ORIENTATION_HORIZONTAL表示水平方向,ViewPager2.ORIENTATION_VERTICAL表示垂直方向。
setPageTransformer:設置二代翻頁視圖的頁面轉換器,以便展示切換動畫。
接下來利用循環適配器搭配二代翻頁視圖,演示看看ViewPager2的界面效果。注意RecyclerView與ViewPager2擁有各自的AndroidX庫,故需修改模塊的build.gradle,在dependencies節點內部補充以下兩行依賴配置:

    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    implementation 'androidx.viewpager2:viewpager2:1.0.0'

接着新建一個活動頁面,往該頁面的XML文件添加如下所示的ViewPager2標籤:

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/vp2_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

因爲ViewPager2仍然需要適配器,所以先編寫每項視圖的佈局文件,下面便是一個XML佈局例子,佈局上方是圖像視圖,下方是文本視圖。

<!-- ViewPager2要求每頁的寬高都必須是match_parent -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <ImageView
        android:id="@+id/iv_pic"
        android:layout_width="match_parent"
        android:layout_height="360dp"
        android:scaleType="fitCenter" />
    <TextView
        android:id="@+id/tv_desc"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

然後給上面的視圖項補充對應的循環適配器代碼,傳入一個商品列表,再展示每個商品的圖片與文字描述。適配器的代碼片段示例如下:

public class MobileRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private Context mContext; // 聲明一個上下文對象
    private List<GoodsInfo> mGoodsList = new ArrayList<GoodsInfo>(); // 聲明一個商品列表
    public MobileRecyclerAdapter(Context context, List<GoodsInfo> goodsList) {
        mContext = context;
        mGoodsList = goodsList;
    }

    // 創建列表項的視圖持有者
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup vg, int viewType) {
        // 根據佈局文件item_mobile.xml生成視圖對象
        View v = LayoutInflater.from(mContext).inflate(R.layout.item_mobile, vg, false);
        return new ItemHolder(v);
    }

    // 綁定列表項的視圖持有者
    public void onBindViewHolder(RecyclerView.ViewHolder vh, final int position) {
        ItemHolder holder = (ItemHolder) vh;
        holder.iv_pic.setImageResource(mGoodsList.get(position).pic);
        holder.tv_desc.setText(mGoodsList.get(position).desc);
    }

    // 定義列表項的視圖持有者
    public class ItemHolder extends RecyclerView.ViewHolder {
        public ImageView iv_pic; // 聲明列表項圖標的圖像視圖
        public TextView tv_desc; // 聲明列表項描述的文本視圖
        public ItemHolder(View v) {
            super(v);
            iv_pic = v.findViewById(R.id.iv_pic);
            tv_desc = v.findViewById(R.id.tv_desc);
        }
    }
}

回到測試頁面的Java代碼,把二代翻頁視圖的排列方向設爲水平方向,並將上述的循環適配器對象設成二代翻頁視圖的適配器。只要以下寥寥幾行代碼就搞定了:

    // 從佈局文件中獲取名叫vp2_content的二代翻頁視圖
    ViewPager2 vp2_content = findViewById(R.id.vp2_content);
    // 設置二代翻頁視圖的排列方向爲水平方向
    vp2_content.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL);
    // 構建一個商品信息列表的循環適配器
    MobileRecyclerAdapter adapter = new MobileRecyclerAdapter(this, GoodsInfo.getDefaultList());
    vp2_content.setAdapter(adapter); // 設置二代翻頁視圖的適配器

運行測試App,水平方向的翻頁過程如下圖所示。


如果把翻頁方向改爲垂直方向,那麼翻頁之時的界面如下圖所示。


以上的效果圖看起來僅僅多了垂直翻頁,稍等片刻給它加上其它特效。先在測試頁面的Java代碼中補充下面幾行:

    // ViewPager2支持展示左右兩頁的部分區域
    RecyclerView cv_content = (RecyclerView) vp2_content.getChildAt(0);
    cv_content.setPadding(Utils.dip2px(this, 60), 0, Utils.dip2px(this, 60), 0);
    cv_content.setClipToPadding(false); // false表示不裁剪下級視圖

重新運行測試App,此時頁面效果如下圖所示,可見除了顯示當前商品之外,左右兩頁也呈現了邊緣區域。


撤銷剛加的邊緣特效代碼,再給測試頁面的Java代碼中補充下面幾行:

    // ViewPager2支持在翻頁時展示切換動畫
    // 創建頁面轉換器,用於計算切換動畫的各項參數
    ViewPager2.PageTransformer animator = new ViewPager2.PageTransformer() {
        @Override
        public void transformPage(@NonNull View page, float position) {
            page.setRotation(position * 360); // 設置頁面的旋轉角度
        }
    };
    vp2_content.setPageTransformer(animator); // 設置二代翻頁視圖的頁面轉換器

重新運行測試App,此時翻頁過程如下面兩圖所示,其中第一張圖爲開始翻頁不久的界面效果,第二張圖爲翻頁即將結束的界面效果,從中可見翻頁時展示了旋轉動畫。

ViewPager2不僅支持循環適配器,同樣支持翻頁適配器,還是新的哦。原先ViewPager採用的翻頁適配器叫做FragmentStatePagerAdapter,而ViewPager2採用了FragmentStateAdapter,兩個適配器的名稱差了個“Pager”。一看名稱不同,用法肯定有差別,儘管它倆都支持碎片Fragment,但具體的方法就不一樣了。
比如下面是採用FragmentStateAdapter的新型適配器代碼例子:

public class MobilePagerAdapter extends FragmentStateAdapter {
    private List<GoodsInfo> mGoodsList = new ArrayList<GoodsInfo>(); // 聲明一個商品列表

    // 碎片頁適配器的構造方法,傳入碎片管理器與商品信息列表
    public MobilePagerAdapter(FragmentActivity fa, List<GoodsInfo> goodsList) {
        super(fa);
        mGoodsList = goodsList;
    }

    // 創建指定位置的碎片Fragment
    @NonNull
    @Override
    public Fragment createFragment(int position) {
        return MobileFragment.newInstance(position,
                mGoodsList.get(position).pic, mGoodsList.get(position).desc);
    }

    // 獲取碎片Fragment的個數
    @Override
    public int getItemCount() {
        return mGoodsList.size();
    }
}


運行測試App觀察到的界面效果跟循環適配器差不多,因爲展示商品信息的場景比較簡單,所以循環適配器和翻頁適配器看不出區別。就實際開發而言,簡單的業務場景適合採用循環適配器,複雜的業務場景適合採用翻頁適配器。
ViewPager有個標籤欄搭檔PagerTabStrip,然而ViewPager2拋棄了PagerTabStrip,直接跟TabLayout搭配了。如果要讓ViewPager聯動TabLayout,得先給ViewPager註冊頁面變更監聽器,一旦監聽到翻頁事件就切換對應的標籤;再給TabLayout註冊標籤選中監聽器,一旦監聽到標籤事件就翻到對應的頁面。現在有了ViewPager2,搭配TabLayout便輕鬆多了,只要一行代碼即可綁定ViewPager2與TabLayout。下面是將二者聯結起來的操作步驟。
1、創建測試頁面,並往頁面的XML文件先後加入TabLayout標籤和ViewPager2標籤,具體內容如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <!-- 標籤佈局TabLayout節點需要使用完整路徑 -->
    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tab_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <!-- 二代翻頁視圖ViewPager2節點也需要使用完整路徑 -->
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/vp2_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
</LinearLayout>

2、打開該頁面的Java代碼,分別獲取TabLayout和ViewPager2的視圖對象,再利用TabLayoutMediator把標籤佈局跟翻頁視圖連爲一體,關鍵代碼示例如下:

    // 從佈局文件中獲取名叫tab_title的標籤佈局
    TabLayout tab_title = findViewById(R.id.tab_title);
    // 從佈局文件中獲取名叫vp2_content的二代翻頁視圖
    ViewPager2 vp2_content = findViewById(R.id.vp2_content);
    // 構建一個商品信息的翻頁適配器
    MobilePagerAdapter adapter = new MobilePagerAdapter(this, mGoodsList);
    vp2_content.setAdapter(adapter); // 設置二代翻頁視圖的適配器
    // 把標籤佈局跟翻頁視圖通過指定策略連爲一體,二者在頁面切換時一起聯動
    new TabLayoutMediator(tab_title, vp2_content, new TabLayoutMediator.TabConfigurationStrategy() {
        @Override
        public void onConfigureTab(TabLayout.Tab tab, int position) {
            tab.setText(mGoodsList.get(position).name); // 設置每頁的標籤文字
        }
    }).attach();

重新運行測試App,初始的演示頁面如下圖所示。


接着點擊上方標籤欄的第二個標籤,此時頁面下方翻到了第二頁商品,如下圖所示。


然後手指在商品處向左滑動,此時翻到了第三頁商品,同時標籤欄也切到了第三個標籤,如下圖所示。由此驗證了標籤佈局與翻頁視圖的確是綁定到一塊了。

 


點此查看Android開發筆記的完整目錄

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章