アンドロイドのTabLayoutとViewPager
このチュートリアルでは、既にこのチュートリアルで実装したTabLayoutの下にViewPagerを実装します。
AndroidのTabLayout ViewPagerの概要
ViewPagersはデータのページをスワイプするために使用されます。通常、フラグメントと一緒に使用されます。前のチュートリアルのレイアウトを以下のように変更しましょう。activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.scdev.tablayoutviewpager.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:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/AppTheme.PopupOverlay" />
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
style="@style/MyStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabGravity="fill"
app:tabMode="fixed" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
android:src="@android:drawable/ic_dialog_email" />
</android.support.design.widget.CoordinatorLayout>
MainActivityにViewPagerを追加する前に、アダプターの設定をしましょう。
public class ViewPagerAdapter extends FragmentPagerAdapter {
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
Fragment fragment = null;
if (position == 0)
{
fragment = new FragmentA();
}
else if (position == 1)
{
fragment = new FragmentB();
}
else if (position == 2)
{
fragment = new FragmentC();
}
return fragment;
}
@Override
public int getCount() {
return 3;
}
@Override
public CharSequence getPageTitle(int position) {
String title = null;
if (position == 0)
{
title = "Tab-1";
}
else if (position == 1)
{
title = "Tab-2";
}
else if (position == 2)
{
title = "Tab-3";
}
return title;
}
}
上記のViewPagerAdapterはFragmentPagerAdapterを拡張しています。それは3つのフラグメントを呼び出し、各ページに1つのフラグメントを持っています。それぞれのフラグメントは、以下に示すようにfragment_list.xmlを持っています。
<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/list"/>
以下に、FragmentA(/B/C).javaのコードを示します。
public class FragmentA extends Fragment {
ListView list;
public FragmentA() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment, container, false);
list = (ListView) view.findViewById(R.id.list);
ArrayList stringList= new ArrayList();
stringList.add("Item 1A");
stringList.add("Item 1B");
stringList.add("Item 1C");
stringList.add("Item 1D");
stringList.add("Item 1E");
stringList.add("Item 1F");
stringList.add("Item 1G");
stringList.add("Item 1H");
stringList.add("Item 1I");
stringList.add("Item 1J");
stringList.add("Item 1K");
stringList.add("Item 1L");
stringList.add("Item 1M");
stringList.add("Item 1N");
stringList.add("Item 1O");
stringList.add("Item 1P");
stringList.add("Item 1Q");
stringList.add("Item 1R");
stringList.add("Item 1S");
stringList.add("Item 1T");
stringList.add("Item 1U");
stringList.add("Item 1V");
stringList.add("Item 1W");
stringList.add("Item 1X");
stringList.add("Item 1Y");
stringList.add("Item 1Z");
CustomAdapter adapter = new CustomAdapter(stringList,getActivity());
list.setAdapter(adapter);
return view;
}
}
上記のListViewに対するCustomAdapter.javaクラスは次の通りです。 (Jōki no ListView ni taisuru CustomAdapter.java kurasu wa tsugi no tōri desu.)
public class CustomAdapter extends ArrayAdapter {
private ArrayList dataSet;
Context mContext;
// View lookup cache
private static class ViewHolder {
TextView txtName;
}
public CustomAdapter(ArrayList data, Context context) {
super(context, R.layout.row_item, data);
this.dataSet = data;
this.mContext = context;
}
@Nullable
@Override
public String getItem(int position) {
return dataSet.get(position);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder; // view lookup cache stored in tag
if (convertView == null) {
viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.row_item, parent, false);
viewHolder.txtName = (TextView) convertView.findViewById(R.id.name);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.txtName.setText(getItem(position));
// Return the completed view to render on screen
return convertView;
}
}
以下にMainActivity.javaクラスが示されています。
public class MainActivity extends AppCompatActivity {
TabLayout tabLayout;
ViewPager viewPager;
ViewPagerAdapter viewPagerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
viewPager = (ViewPager) findViewById(R.id.viewPager);
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(viewPagerAdapter);
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
}
}
上記のコードでは、setupWithViewPager()メソッドを使用して、TabLayoutとViewPagerを結び付けています。FragmentPagerAdapterのgetPageTitle()メソッドを使用して、各タブのタイトルを設定しています。上記のコードを実行した場合の出力を見てみましょう。質問:なぜToolBarが設定されたscrollFlagsに従ってスクロールしないのですか?それはListViewのせいです。CoordinatorLayoutはListViewをサポートしていません(Material Designの一部ではありません)し、スクロールのジェスチャーもサポートしていません。そのため、代わりにRecyclerViewを使用することを推奨しています。注意:CoordinatorLayoutのアクティビティに属するフラグメントは、スクロールのジェスチャーが正しく機能するようにするために、NestedScrollViewまたはRecyclerViewを親として使用する必要があります。アプリケーション内のListViewの実装を置き換える前に、現在のフラグメントのレイアウトを下記のようにNestedScrollViewで包みます。fragment_list.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ListView xmlns:android="https://schemas.android.com/apk/res/android"
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.v4.widget.NestedScrollView>
さて、アプリケーションの挙動を確認してみましょう。おっと、スクロールは修正されましたが、ListViewは今は一行しか表示されません。したがって、私たちのマテリアルデザインのビュータイプではListViewは使用しない方が良いですね。さあ、アプリケーションを修正しましょう。
アンドロイドのTabLayout ViewPagerプロジェクトの構造。
AndroidのTabLayout ViewPagerの例のコード
以下はactivity_main.xml、MainActivity.java、ViewPagerAdapter.javaのクラスは変更されていません。では、フラグメントを見てみましょう。フラグメントのレイアウトは以下の通りです。fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="https://schemas.android.com/apk/res/android" />
以下にFragmentA(/B/C).javaが与えられています。
package com.scdev.tablayoutviewpager;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class FragmentA extends Fragment {
RecyclerView recyclerView;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(
R.layout.fragment, container, false);
return rootView;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
String[] items = getResources().getStringArray(R.array.tab_A);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(items);
recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
}
}
データを表示するために、strings.xmlファイルにデータを移動しました。そこでデータが定義されています。
<resources>
<string name="app_name">TabLayoutViewPager</string>
<string name="action_settings">Settings</string>
<string-array name="tab_A">
<item>Item 1A</item>
<item>Item 1B</item>
</string-array>
<string-array name="tab_B">
<item>Item 2A</item>
</string-array>
</resources>
注意:私たちは、フラグメントのコードロジックを最適化しました。これにより、ビューが作成されると、アダプターにデータがセットされ、表示されるようになりました。RecyclerViewAdapter.javaには、文字列の配列が引数としてあります。そのコードは以下の通りです。
public class RecyclerViewAdapter extends RecyclerView.Adapter {
String[] items;
public RecyclerViewAdapter(String[] items) {
this.items = items;
}
@Override
public TextItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_view_list_item, parent, false);
return new TextItemViewHolder(view);
}
@Override
public void onBindViewHolder(TextItemViewHolder holder, int position) {
holder.bind(items[position]);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemCount() {
return items.length;
}
}
上記のコードでは、リストアイテムに似たレイアウトを持つカスタムRecyclerViewHolderクラスを追加しました。TextItemViewHolder.javaクラスは以下のようになります。
public class TextItemViewHolder extends RecyclerView.ViewHolder {
private TextView textView;
public TextItemViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.list_item);
}
public void bind(String text) {
textView.setText(text);
}
}
上記のカスタムViewHolderのレイアウトは、recycler_view_list_item.xmlです。 (Jouki no kasutamu ViewHolder no reirautto wa, recycler_view_list_item.xml desu.)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/list_item"
android:textSize="18sp"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingRight="8dp"
android:paddingLeft="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<View
android:id="@+id/separator"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#858585" />
</LinearLayout>
アプリケーションの動作結果は以下のように表示されます。レイアウトの構造はWhatsAppアプリケーションに似ています。より似せるために、以下の変更を行ってください。
- Import and add the two menu icon drawables
- Inflate them in the MainActivity.java in the onCreateOptionsMenu()
- Change the colorPrimary and colorPrimaryDark to #00897B and #00796B respectively
メニューレイアウトを拡張するために、MainActivity.javaに以下のメソッドを追加してください。
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return super.onCreateOptionsMenu(menu);
}
メニューのメイン.xmlは次のようになっています。
<menu xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
tools:context="com.scdev.tablayoutviewpager.MainActivity">
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:title="@string/action_settings"
app:showAsAction="never" />
<item
android:id="@+id/action_search"
android:orderInCategory="100"
android:title="@string/action_settings"
android:icon="@drawable/search"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_add"
android:orderInCategory="100"
android:title="@string/action_settings"
android:icon="@drawable/add"
app:showAsAction="ifRoom" />
</menu>
上記の変更を行うと、このようなものができあがります。このチュートリアルはこれで終了です。Android TabLayoutViewPagerプロジェクトは以下のリンクからダウンロードできます。
Android TabLayout ViewPager プロジェクトをダウンロードする。