TabLayout + ViewPager + FontAwesomeでタブ遷移を実装してみた
前回の記事の続き
[Android]フラグメントについてまとめ - 社会人1年目文系エンジニアのブログ
TabLayout + ViewPager + FontAwesomeを使って以下のようなタブ遷移を実装しました
アクティビティ
public class MainActivity extends AppCompatActivity { // タブメニューのインデックス private static final int INDEX_HOME = 0; private static final int INDEX_DIALOG = 1; private static final int INDEX_WEBVIEW = 2; // タブレイアウト private TabLayout mTabLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // TabLayoutにTabを追加 mTabLayout = (TabLayout) findViewById(R.id.tablayout); mTabLayout.addTab(mTabLayout.newTab()); mTabLayout.addTab(mTabLayout.newTab()); mTabLayout.addTab(mTabLayout.newTab()); // ViewPager ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager); // 各コンテンツとなるフラグメントをセットするアダプターをViewPagerにセット // Fragmentを操作するためにコンストラクタの引数にFragmentManagerを渡しスーパークラスにセットします。 MyFragmentPagerAdapter pagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager()); // アダプターに各ページ要素となるフラグメントを追加 pagerAdapter.addFragment(SimpleTextFragment.newInstance(INDEX_HOME, "ホーム画面")); pagerAdapter.addFragment(SimpleTextFragment.newInstance(INDEX_DIALOG, "ダイアログフラグメント画面")); pagerAdapter.addFragment(SimpleTextFragment.newInstance(INDEX_WEBVIEW, "WEBVIEW画面")); // ViewPagerにアダプタをセット viewPager.setAdapter(pagerAdapter); // TabLayoutとViewPagerをバインド mTabLayout.setupWithViewPager(viewPager); // fontawesome使いたいのでタブレイアウトをカスタム setUpCustomTab(); } /** * カスタムタブレイアウトをセット */ private void setUpCustomTab() { for (int i = 0; i < mTabLayout.getTabCount(); i++) { TabLayout.Tab tab = mTabLayout.getTabAt(i); if (tab == null) { continue; } if (i == INDEX_HOME) { // ホーム tab.setCustomView(createCustomTabView(getString(R.string.fa_home))); } else if (i == INDEX_DIALOG) { // ダイアログフラグメント tab.setCustomView(createCustomTabView(getString(R.string.fa_commenting))); } else if (i == INDEX_WEBVIEW) { // WebView tab.setCustomView(createCustomTabView(getString(R.string.fa_globe))); } } } /** * タブごとにレイアウトをインフレートしてmenuアイコンをセットしたビューを返します。 * * @param icon fontawesomeのUnicode * @return View カスタムビュー */ private View createCustomTabView(String icon) { // カスタムタブビューのレイアウトをインフレートします。 LayoutInflater inflater = LayoutInflater.from(this); View customView = inflater.inflate(R.layout.tab_item_layout, null); // アセットから読み込んだfontawesomeをビューにセットします。 TextView tabIcon = (TextView) customView.findViewById(R.id.tab_icon); Typeface font = Typeface.createFromAsset(getAssets(), "fontawesome-webfont.ttf"); tabIcon.setTypeface(font); tabIcon.setText(icon); return customView; } }
fontawesomeを使う方法は以下参照
Android アプリで Font Awesome を利用する – アカベコマイリ
アダプタ
public class MyFragmentPagerAdapter extends FragmentStatePagerAdapter { private List<Fragment> mFragments = new ArrayList<>(); public MyFragmentPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return mFragments.get(position); } @Override public int getCount(){ return mFragments.size(); } public void addFragment(Fragment ft) { mFragments.add(ft); } }
onCreateで開発者がaddFragmentを書くことが強制されてないのであんまりよくない気もする。
コンストラクタで渡したほうがいいのかもしれない
各ページのフラグメント
public class SimpleTextFragment extends Fragment { /** * staticファクトリーメソッド * Bundleで値をセットしたこのクラスのインスタンスを返します。 * * @param index ページ番号 * @param title 画面のタイトル * @return SimpleTextFragment フラグメント */ public static SimpleTextFragment newInstance(int index,String title) { Bundle args = new Bundle(); args.putString("title",title); args.putInt("index",index); SimpleTextFragment fragment = new SimpleTextFragment(); fragment.setArguments(args); return fragment; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.simple_fragment_layout,container,false); Bundle args = getArguments(); String title = args.getString("title"); ((TextView) view.findViewById(R.id.title)).setText(title); return view; } }
今回は遷移が実装できればよかったので同じクラスの別インスタンスをアダプタにセットしてるだけです
メインレイアウト
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" android:background="@color/bg_gray" tools:context="jp.recruit.practicefragment.MainActivity"> <android.support.v4.view.ViewPager android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/viewpager"> <android.support.design.widget.TabLayout android:layout_width="match_parent" android:layout_height="wrap_content" app:tabBackground="@color/white" android:id="@+id/tablayout" app:tabIndicatorHeight="3dp" android:layout_gravity="top"/> </android.support.v4.view.ViewPager> </LinearLayout>
公式参照
TabLayout | Android Developers
タブレイアウト
<?xml version="1.0" encoding="utf-8"?> <LinearLayout android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:textSize="25dp" android:textColor="@drawable/icon_selector" android:id="@+id/tab_icon" /> </LinearLayout>
タブ一個のレイアウト。
このテキストビューにfontawesome指定でtextをセットする
drawableじゃないから変なメモリリークとかおきないし、解像度別に画像用意しなくていい。
セレクタ
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_selected="true" android:color="@color/colorAccent" /> <item android:state_selected="false" android:color="@color/icon_gray" /> </selector>
タブが選択されていたら色を変えるシンプルなセレクタ
感想
ただタブ遷移するだけならすぐ実装できてすごいなぁと思いました。
公式のデザインガイド的にはタブはページ上部に設置するようにとのことです。
多分キーボードとの兼ね合いだと思います。
次回
1個のタブの中でさらに遷移したい場合viewpagerではどうやって実装するのがベストプラクティスなんだろう。。
というのを割とずっと考えているので次回はそのあたりまとめたいと思います