Takahiro Octopress Blog

-1から始める情弱プログラミング

Android Studio2.0: TabLayoutを使ってみよう!

TabHostとTabLayoutについて

前回、AndroidでTabHostを使ったアプリの作り方について見ていきましたが、本日は TabLayout を使ったアプリの作り方を見ていきたいと思います。
なぜ似たような名前のクラスがあるのかと思いますよね?
実はTabHostはもう随分前から非推奨とされており、同様の機能を実装するために TabLayout が提供されているようなんです。

もう少し、詳しく説明すると、
『Google I/O 2014』にてMaterial Designが発表されました。
(これはGoogleが提唱するパソコンやスマートフォン向けのアプリまたはWebサイト等の新しいデザイン方式です。)

そして、『Google I/O 2015』にてMaterial Designを実現するためのサポートライブラリ『 Android Design Support Library 』が発表されました。
TabLayout はこの Android Design Support Library に含まれるコンポーネントの1つなのです。

また、現在(2016/01/30時点)、公式でリリースされているAndroid Studioでは自身でbuild.gradlecompile 'com.android.support:design:23.+'と追記する必要がありますが、Preview版として提供されている Android Studio 2.0 では、Blank Activityですらデフォルトで Android Design Support Library を利用するように組み込まれています。

さて、今日はそんな Android Design Support Library のコンポーネントの1つ TabLayout について見ていきたいと思います。

TabLayoutを使ってみよう!

TabHostを書いた時と同じ書式で書いていきます。

1. Android StudioでBlank Activityを選択して、プロジェクトを新規作成
下記のようなプロジェクト構成ができあがります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
app
 ┣━━ manifests
     ┗━━ AndroidManifest.xml
 ┣━━ java
     ┣━━ com.example.takahiro.tabhostapplication
           ┗━━ MainActivity
     ┣━━ com.example.takahiro.tabhostapplication(androidTest)
           ┗━━ ApplicationTest
     ┗━━ com.example.takahiro.tabhostapplication(test)
            ┗━━ ExampleUnitTest
 ┗━━ res
      ┣━━ drawable
      ┣━━ layout
           ┣━━ activity_main.xml
           ┗━━ content_main.xml
      ┣━━ menu
      ┣━━ mipmap
      ┗━━ values

2.content_main.xmlにTabLayoutを追加
ページ遷移のためにViewPagerも追加しておきます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  ....
  tools:showIn="@layout/activity_main">

  <android.support.design.widget.TabLayout
      android:id="@+id/tabs"
      android:layout_width="match_parent"
      android:layout_height="wrap_content" />

  <android.support.v4.view.ViewPager
      android:id="@+id/pager"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_below="@+id/tabs" />
</RelativeLayout>

因みに、activity_main.xmlは以下にしています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:fitsSystemWindows="true"
  tools:context="com.example.takahiro.tablayoutsample2.MainActivity">

  <android.support.design.widget.AppBarLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:theme="@style/AppTheme.AppBarOverlay">

      <android.support.v7.widget.Toolbar
          android:id="@+id/toolbar"
          android:layout_width="match_parent"
          android:layout_height="?attr/actionBarSize"
          android:background="?attr/colorPrimary"
          app:popupTheme="@style/AppTheme.PopupOverlay" />

  </android.support.design.widget.AppBarLayout>

  <include layout="@layout/content_main" />
</android.support.design.widget.CoordinatorLayout>

デフォルトでFloatingActionButtonが作成されますが、こちらは今回不要なので削除しています。

3.表示ページ用にFragmentを継承したPageFragmentを作成
メニューからBlankFragmentを追加すると、ある程度デフォルトで処理を作成してくれます。
まずはPageFragment.javaファイルは下記に一部修正しました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package com.example.takahiro.tablayoutapplication;

import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class PageFragment extends Fragment {

  private static final String ARG_PARAM = "page";
  private String mParam;
  private OnFragmentInteractionListener mListener;
  
  // コンストラクタ
  public PageFragment() {
  }

  public static PageFragment newInstance(int page) {
      PageFragment fragment = new PageFragment();
      Bundle args = new Bundle();
      args.putInt(ARG_PARAM, page);
      fragment.setArguments(args);
      return fragment;
  }
  
  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      if (getArguments() != null) {
          mParam = getArguments().getString(ARG_PARAM);
      }
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
      // Inflate the layout for this fragment
      int page = getArguments().getInt(ARG_PARAM, 0);
      View view = inflater.inflate(R.layout.fragment_page, container, false);
      (TextView)view.findViewById(R.id.textView)).setText("Page" + page);
      
      return view;
  }

  public void onButtonPressed(Uri uri) {
      if (mListener != null) {
          mListener.onFragmentInteraction(uri);
      }
  }

  @Override
  public void onAttach(Context context) {
      super.onAttach(context);
      if (context instanceof OnFragmentInteractionListener) {
          mListener = (OnFragmentInteractionListener) context;
      } else {
          throw new RuntimeException(context.toString()
              + " must implement OnFragmentInteractionListener");
      }
  }

  @Override
  public void onDetach() {
      super.onDetach();
      mListener = null;
  }

  public interface OnFragmentInteractionListener {
      void onFragmentInteraction(Uri uri);
  }
}

続いて、XMLファイルは下記です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context="com.example.takahiro.tablayoutapplication.PageFragment">
  
  <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Page"
      android:id="@+id/textView"
      android:layout_centerVertical="true"
      android:layout_centerHorizontal="true"
      android:textSize="32sp" />
</RelativeLayout>

4.MainActivity.javaにTabLayoutとViewPagerを組み込み

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public class MainActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener,
      PageFragment.OnFragmentInteractionListener {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
      setSupportActionBar(toolbar);

      // xmlからTabLayoutの取得
      TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
      // xmlからViewPagerを取得
      ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
      // ページタイトル配列
      final String[] pageTitle = {"HOME", "EVENT", "SETTING"};

      // 表示Pageに必要な項目を設定
      FragmentPagerAdapter adapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
          @Override
          public Fragment getItem(int position) {
              return PageFragment.newInstance(position + 1);
          }

          @Override
          public CharSequence getPageTitle(int position) {
              return pageTitle[position];
          }

          @Override
          public int getCount() {
              return pageTitle.length;
          }
      };

      // ViewPagerにページを設定
      viewPager.setAdapter(adapter);
      viewPager.addOnPageChangeListener(this);

      // ViewPagerをTabLayoutを設定
      tabLayout.setupWithViewPager(viewPager);
  }
  ....

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

  @Override
  public void onPageSelected(int position) {
  }

  @Override
  public void onPageScrollStateChanged(int state) {
  }
  
  @Override
  public void onFragmentInteraction(Uri uri) {
  }
}

これでタブによる画面遷移が完成です。

TabLayoutによるアプリ画面

スワイプを禁止した単純なTab遷移にするためには

筆者のTabの印象には、横スワイプによる画面切替は含まれていませんでした。
なので、スワイプによる画面切替を禁止してみましょう。
HoldableViewPagerをまんま使います。

ViewPagerを継承したHoldableViewPagerを作成します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.example.takahiro.tablayoutapplication;

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;

public class HoldableViewPager extends ViewPager {

  // スワイプの禁止フラグ(true: スワイプ禁止, false: スワイプOK)
  boolean isSwipeHold = false;

  public void setSwipeHold(boolean enabled) {
      isSwipeHold = enabled;
  }
  
  // コンストラクタ
  public HoldableViewPager(Context context) {
      super(context);
  }

  // コンストラクタ
  public HoldableViewPager(Context context, AttributeSet attributeSet) {
      super(context, attributeSet);
  }

  @Override
  public boolean onTouchEvent(MotionEvent motionEvent) {
      if(isSwipeHold) {
          // スワイプ禁止の場合
          return false;
      }

      return super.onTouchEvent(motionEvent);
  }

  @Override
  public boolean onInterceptTouchEvent(MotionEvent event) {
      if(isSwipeHold) {
          // スワイプ禁止の場合
          return false;
      }

      return super.onInterceptTouchEvent(event);
  }
}

このHoldableViewPagerMainActivity.javaで使います。
使い方は簡単でViewPagerHoldableViewPagerで置き換えて、isSwipeHoldをtrueにするだけです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
....

@Override
protected void onCreate(Bundle savedInstanceState) {
  ....
  // xmlからTabLayoutの取得
  TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
  // xmlからViewPagerを取得
  HoldableViewPager viewPager = (HoldableViewPager)findViewById(R.id.pager);
  // スワイプ禁止設定の追加
  viewPager.setSwipeHold(true);
  ....
}
....

また、content_main.xmlViewPagerからHoldableViewPagerに変更する必要があります。

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  ...
  <com.example.takahiro.tablayoutapplication.HoldableViewPager
      android:id="@+id/pager"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_below="@+id/tabs"
   />
</RelativeLayout>

本日はここまで。

Comments