Java
Android
AndroidStudio
android開発

[Android] チュートリアルに使えそうなViewPagerを作りたい

はじめに

アプリの初期起動時にチュートリアルを表示したいと思った時に、何か直感的に操作・理解できそうなものはないかと探したところ、「ViewPager」なるものに出会いました。

ライブラリを突っ込めばそれっぽいものが簡単にできるそうですが、いざカスタマイズするとなると不便になる可能性もあるので、素人ながら自力で組んでみました。

page.gif

準備

「ViewPager」API22からの利用となるそうなので、CompileSdkVersion22以上にしましょう。また今回はIndicatorも表示したいので、design support libraryを導入します。

app.build
apply plugin: 'com.android.application'

android {
  compileSdkVersion 26
  buildToolsVersion "26.0.1"
  defaultConfig {
    ...
  }
  buildTypes {
    release {
      ...
    }
    debug {
      ...
    }
  }
}

dependencies {
  compile fileTree(include: ['*.jar'], dir: 'libs')
  compile 'com.android.support:appcompat-v7:26.0.0-alpha1'
  compile 'com.android.support:support-v4:26.0.0-alpha1'
  compile 'com.android.support:design:26.0.0-alpha1'
}

土台を作る

「ViewPager」は土台の上に複数のFragmentを持ち、ユーザー操作によりそれらを順次表示してくような動きをしています。

なので今回は、土台となる1つのActivityViewPagerIndicatorを配置し、現在のpositionによって表示するFragmentを切り替えてくれるAdapterを噛ませれば良いかと思います。

では実際に土台となるActivityを作っていきます。

MainActivity.java
public class MainActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener, View.OnClickListener {
  private final static int PAGE_NUM = 3;
  private ViewPager viewPager;
  private TextView textLeft;
  private TextView textRight;

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

    viewPager = (ViewPager) findViewById(R.id.pager);
    PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager());  // カスタムAdapter
    viewPager.setAdapter(adapter);
    viewPager.addOnPageChangeListener(this);  // ページ遷移によるListenerを追加

    TabLayout tabLayout = (TabLayout) findViewById(R.id.indicator);
    tabLayout.setupWithViewPager(viewPager, true);

    textLeft = (TextView) findViewById(R.id.text_left);
    textLeft.setOnClickListener(this);  // フッターテキスト(左)のクリックListenerを追加
    textRight = (TextView) findViewById(R.id.text_right);
    textRight.setOnClickListener(this);  // フッターテキスト(右)のクリックListenerを追加
  }

  @Override
  public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
  }

  @Override
  public void onPageSelected(int position) {  // フッターテキストの切り替え
    if (position == 0) {
      textLeft.setText("Skip");
    } else {
      textLeft.setText("Back");
    }

    if (position == (PAGE_NUM - 1)) {
      textRight.setText("Go!");
    } else {
      textRight.setText("Next");
    }
  }

  @Override
  public void onPageScrollStateChanged(int state) {
  }

  @Override
  public void onClick(View view) {  // フッターテキストのクリック時動作
    switch (view.getId()) {
      case R.id.text_left:
        if (viewPager.getCurrentItem() != 0) {  // 始めのページで無ければ一枚戻る
          viewPager.setCurrentItem(viewPager.getCurrentItem() - 1, true);
        }
        break;
      case R.id.text_right:
        if (viewPager.getCurrentItem() != PAGE_NUM) {  // 最後のページで無ければ一枚進む
          viewPager.setCurrentItem(viewPager.getCurrentItem() + 1, true);
        }
        break;
    }
  }

  private class PagerAdapter extends FragmentPagerAdapter {  // カスタムAdapter
    PagerAdapter(FragmentManager manager) {
      super(manager);
    }

    @Override
    public Fragment getItem(int position) {
      switch (position) {  // 現在のPositionにより表示するFragmentを切り替え
        case 0:
          return new FirstFragment();
        case 1:
          return new SecondFragment();
        case 2:
          return new ThirdFragment();
      }
      return null;
    }

    @Override
    public int getCount() {
      return PAGE_NUM;
    }
  }
}

次にViewを作成します。

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                android:layout_width="match_parent"
                android:layout_height="match_parent">

  <android.support.v4.view.ViewPager
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_above="@+id/footer"/>

  <RelativeLayout
    android:id="@+id/footer"
    android:layout_width="match_parent"
    android:layout_height="60dp"
    android:layout_alignParentBottom="true"
    android:background="#3F51B5">

    <TextView
      android:id="@+id/text_left"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentStart="true"
      android:layout_centerVertical="true"
      android:layout_marginStart="30dp"
      android:padding="15dp"
      android:text="Skip"
      android:textColor="#FFFFFF"
      android:textSize="18sp"/>

    <android.support.design.widget.TabLayout
      android:id="@+id/indicator"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_centerHorizontal="true"
      android:layout_centerVertical="true"
      app:tabBackground="@drawable/indicator_selector"
      app:tabGravity="center"
      app:tabIndicatorHeight="0dp"/>

    <TextView
      android:id="@+id/text_right"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_alignParentEnd="true"
      android:layout_centerVertical="true"
      android:layout_marginEnd="30dp"
      android:padding="15dp"
      android:text="Next"
      android:textColor="#FFFFFF"
      android:textSize="18sp"/>

  </RelativeLayout>

</RelativeLayout>

今回Indicatorを表示するためにdesign support libraryTabLayoutを用いています。
またapp:tabBackground="@drawable/indicator_selector"と指定する事でIndicatorを実装しています。
以下そのselectorになります。

indicator_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_selected="true">
    <shape
      android:innerRadius="0dp"
      android:shape="ring"
      android:thickness="4dp"
      android:useLevel="false">
      <solid android:color="#DEDCDB"/>
    </shape>
  </item>
  <item>
    <shape
      android:innerRadius="0dp"
      android:shape="ring"
      android:thickness="2dp"
      android:useLevel="false">
      <solid android:color="#A59E99"/>
    </shape>
  </item>
</selector>

表示するページを作る

お好きなページ、つまりFragmentを作れば良いだけです!
なのでここでは割愛させていただきます...

終わりに

今回は追加ライブラリを導入せずに自作で作りましたが、世の中は便利なもので、探せばそれっぽいものがいっぱい転がってます(笑) それでも好みのものが見つからなかった場合には是非参考にしていただければ幸いです。

次はもっとリッチな感じに仕上げたいですね⊂((・⊥・))⊃
・視差効果
・アニメーション
・入出力
この辺りにチャレンジしていきたいところ!