Android Tips #36 PagerTabStrip を使って Google Play ストア風のアプリを作ってみる

2013.01.10

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

PagerTabStrip とは

PagerTabStrip は ViewPager にタブ機能を追加するための View です。Support Package に含まれているので Android 1.6 (APIレベル4) から使用することができます。代表的な例として Google Play ストアアプリのアプリ一覧画面で使われています。

google_play

今回は PagerTabStrip を使ったサンプルとして Google Play ストアアプリを真似た下図のようなアプリを作ってみたので、その手順を解説したいと思います!

pager_tab_strip01

PagerTabStrip の使いかた

1. レイアウトを作る

まずはレイアウトを作ります。ViewPager にタブを表示するには、以下のように ViewPager に PagerTabStrip をネストします。これでタブを表示するための最低限の実装は完了したも同然です。簡単ですね!

activity_main.xml

<android.support.v4.view.ViewPager 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <android.support.v4.view.PagerTabStrip
        android:id="@+id/strip"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#333333"
        android:paddingBottom="6dp"
        android:paddingTop="6dp" />

</android.support.v4.view.ViewPager>

2. Fragment を作る

次に ViewPager で表示する画面を Fragment で作ります。今回は応用編ということで複数の Fragment を扱ってみたいと思います。

GridView の Fragment を作る

まずひとつめは GridView を表示する Fragment です。以下のクラスを作成しました(解説は割愛します)。GridView の作りかたはこちらを、Fragment の作りかたはこちらを参照してください。

データが加わると下図のように表示されます。

pager_tab_strip01

RelativeLayout の Fragment を作る

次にもうひとつ、 RelativeLayout の Fragment を作ります。データなどは入れずに、ただ ImageView を Google Play ストアの「おすすめページ」風にいくつか並べてみました。

pager_tab_strip02

3. FragmentPagerAdapter を実装する

次に PagerAdapter を実装します。今回はページに Fragment を使いたいと思うので FragmentPagerAdapter を使います。FragmentPagerAdapter の使いかたはこちらに掲載済みなので参照してください。応用編ということで、今回は複数の Fragment を取り扱ってみます。まずは以下のようなページ情報の DTO クラスをつくります。

PageItem.java

package jp.classmethod.android.sample.playstore;

import java.util.ArrayList;

/**
 * ページのアイテム.
 */
public class PageItem {
    
    /** GridView の Fragment の Id. */
    public static final int GRID = 0;
    /** RelativeLayout の Fragment の Id. */
    public static final int RELATIVE = 1;
    
    /** ページ名. */
    public String title;
    /** Fragment の種類. */
    public int fragmentKind;
    /** アプリケーションのリスト. */
    public ArrayList<App> appList;

}

次に FragmentPagerAdapter を実装します。タブにページの名前を表示するには getPageTitle() をオーバーライドします。ページ毎のデータは PageItem にまとめているので PageItem#title の値を返すようにします。また getItem() メソッド内では PageItem#fragmentKind をもとに返す Fragment を変えています。GridViewFragment を返す場合は Bundle に PageItem#appList をセットして setArguments() で渡すようにしています。

CustomFragmentPagerAdapter.java

package jp.classmethod.android.sample.playstore;

import java.util.ArrayList;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

/**
 * FragmentPagerAdapter.
 */
public class CustomFragmentPagerAdapter extends FragmentPagerAdapter {

    /** {@link PageItem} のリスト. */
    private ArrayList<PageItem> mList;
    
    /**
     * コンストラクタ.
     * @param fm {@link FragmentManager}
     */
    public CustomFragmentPagerAdapter(FragmentManager fm) {
        super(fm);
        mList = new ArrayList<PageItem>();
    }
    
    @Override
    public Fragment getItem(int position) {
        PageItem item = mList.get(position);
        if (PageItem.RELATIVE == item.fragmentKind) {
            // RelativeLayout の Fragment
            return new RecommendFragment();
        }
        // GridView の Fragment
        GridViewFragment gridViewFragment = new GridViewFragment();
        // Bundle を作成
        Bundle bundle = new Bundle();
        bundle.putSerializable("list", item.appList);
        gridViewFragment.setArguments(bundle);
        return gridViewFragment;
    }
    
    @Override
    public CharSequence getPageTitle(int position) {
        return mList.get(position).title;
    }

    @Override
    public int getCount() {
        return mList.size();
    }
    
    /**
     * アイテムを追加する.
     * @param item {@link PageItem}
     */
    public void addItem(PageItem item) {
        mList.add(item);
    }
    
}

あとは Activity を実装して終わりです!オススメページ、人気アプリページ、新着アプリページを作ってみました。App のリストは (めんどうなので) 同じものを使いまわしていますが、本来であればそれぞれのリストを作って渡します。

MainActivity.java

package jp.classmethod.android.sample.playstore;

import java.util.ArrayList;

import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.view.PagerTabStrip; import android.support.v4.view.ViewPager; import android.util.TypedValue;

/** * ViewPager を表示する Activity. */ public class MainActivity extends FragmentActivity {

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);

ViewPager pager = (ViewPager) findViewById(R.id.pager);

// PagerTitleStrip のカスタマイズ PagerTabStrip strip = (PagerTabStrip) findViewById(R.id.strip); strip.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); strip.setTextColor(0xff9acd32); strip.setTextSpacing(50); strip.setNonPrimaryAlpha(0.3f); strip.setDrawFullUnderline(true); strip.setTabIndicatorColor(0xff9acd32);

// ViewPager の Adapter CustomFragmentPagerAdapter adapter = new CustomFragmentPagerAdapter(getSupportFragmentManager());

// GridView の Adapter ArrayList appList = new ArrayList(); for (int i = 0; i < 30; i++) { App item = new App(); item.title = "App" + i; item.description = "This app is " + i + "."; item.company = "Company" + i; item.rate = (float) Math.random() * 5; item.value = (int) Math.floor((Math.random() * (500 - 80 + 1))) + 80; appList.add(item); } // 各ページアイテム(おすすめアプリ) PageItem recommend = new PageItem(); recommend.title = "Recommend App"; recommend.fragmentKind = PageItem.RELATIVE; adapter.addItem(recommend); // 各ページアイテム(人気アプリ) PageItem popular = new PageItem(); popular.title = "Popular App"; popular.fragmentKind = PageItem.GRID; popular.appList = appList; adapter.addItem(popular); // 各ページアイテム(新着アプリ) PageItem newest = new PageItem(); newest.title = "Newest App"; newest.fragmentKind = PageItem.GRID; newest.appList = appList; adapter.addItem(newest); pager.setAdapter(adapter); } } [/java]

実行すると以下のようになります!

pager_tab_strip03

サンプルソース

今回作成したアプリを github で公開しました。ぜひ参考にしてください!

suwa-yuki/PlayStoreSample

PagerTabStrip のカスタマイズ

PagerTabStrip は文字色や文字サイズなどの表示をカスタマイズすることができます。以下にまとめてみました。

文字色を変更する

文字色の変更には PagerTabStrip#setTextColor() を使います。

customize01

文字サイズを変更する

文字サイズの変更には PagerTabStrip#setTextSize() を使います。第一引数には dp や sp といった単位の種類の定数クラス TypedValue から任意の定数を渡します。

customize02

非表示のページタイトルの透過度を変更する

非表示中(現在表示されているページの前後)のページタイトルの透過度を変更するには PagerTabStrip#setNonPrimaryAlpha() を使います。

customize03

ページタイトルの間隔を変更する

PagerTabStrip#setTextSpacing() でページタイトルとページタイトルの間隔を変更することができます。これは左にフリックしたときに前に表示していたページタイトルが新しいページタイトルに押し出される間隔になります。

customize04

ページタイトルの配置を変更する

ページタイトルの配置場所を PagerTabStrip#setGravity() で変更することができます。Vertical のみ有効になります。

customize05

ページタイトルのインジケータの色を変更する

インジケータとはページタイトルの下に表示されている太い線のことです。 PagerTabStrip#setTabIndicatorColor() で好きな色に変更できます。

customize06

下線の表示/非表示を変更する

PagerTabStrip#setDrawFullUnderline() で下線を表示するか否かを設定できます。

customize07

背景色を変更する

背景色を変更するには PagerTabStrip#setBackgroundColor() または PagerTabStrip#setBackgroundResource() を使います。

【customize08.png】 customize08

まとめ

PagerTabStrip 自体の実装は ViewPager にネストするだけなのでとても簡単です!あとは表示を少しカスタマイズできるところが良いですね〜。何より Android 1.6 から利用できるところが素敵です。画面を分割するために ViewPager を使おうとしているケースで特に重宝すると思います。ぜひ使ってみてください。また PagerTabStrip をもっとシンプルにしたい場合は親クラスである PagerTitleStrip があるのでそちらの使用も検討してみても良いと思います。

参考