よくあるこういったUIのやつ
コンテンツ部分を横スワイプでタブが左右に切り替わる
使用するコンポーネント
ViewPager
スワイプに応じてページングされたFragmentを生成し、自動でアタッチする。
TabLayout
TabのUI表現及び、リスナーを管理する。また、生成したViewPagerをセットすることでViewPagerの挙動に応じてタブを切り替えることが可能。
導入
app/buile.gradle
implementation 'com.android.support:design:28.0.0'
implementation 'com.google.android.material:material:1.0.0'
こちらを入れてしまうとAndroidXのコンポーネントと競合しビルドが通らなかった。
Manifest merger failed : Attribute application@appComponentFactory value=(android.support.v4.app.CoreComponentFactory) from [com.android.support:support-compat:28.0.0] AndroidManifest.xml:22:18-91
TabLayoutとViewPagerの配置
TabLayoutとViewPagerを配置するのみでよい。また、TabItemは後述するViewPagerで生成されるので、ここで記載の必要はない
xml version="1.0" encoding="utf-8"
<androidsupportconstraintConstraintLayout
xmlnsandroid="http://schemas.android.com/apk/res/android"
xmlnstools="http://schemas.android.com/tools"
xmlnsapp="http://schemas.android.com/apk/res-auto"
androidlayout_width="match_parent"
androidlayout_height="match_parent"
toolscontext=".Posts.MainActivity">
<androidsupportdesignwidgetTabLayout
androidlayout_width="0dp"
androidlayout_height="wrap_content"
applayout_constraintEnd_toEndOf="parent"
applayout_constraintStart_toStartOf="parent"
applayout_constraintTop_toTopOf="parent" androidid="@+id/tabLayout">
</androidsupportdesignwidgetTabLayout>
<androidsupportv4viewViewPager
androidid="@+id/viewPager"
androidlayout_width="match_parent"
androidlayout_height="0dp" applayout_constraintTop_toBottomOf="@+id/tabLayout"
applayout_constraintBottom_toBottomOf="parent" applayout_constraintStart_toStartOf="parent"
applayout_constraintEnd_toEndOf="parent"/>
</androidsupportconstraintConstraintLayout>
Fragmentの定義
Fragmentはタブ、スワイプで切り替わるコンテンツ部分の定義をすればよい。R.layout.fragment_personal_posts
にレイアウトを記述しているものとする。
class Tab1PostsFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_personal_posts, container, false)
}
companion object {
@JvmStatic
fun newInstance() =
PersonalPostsFragment().apply {
arguments = Bundle().apply {
}
}
}
}
Tab1PostsFragment
と同様にTab2PostsFragment
も定義しておく。
Tab生成、制御の実装
Activityまたは上記2つのFragmentの親となるFragmentに記述する。
Tabの生成、制御はViewPagerのAdapterが管理する
viewPager.adapter = object : FragmentPagerAdapter(supportFragmentManager){
override fun getCount(): Int { ... }
override fun getItem(position: Int): Fragment { ... }
override fun getPageTitle(position: Int): CharSequence? { ... }
}
FragmentPagerAdapter
は一度作成されたFragmentはViewPagerが保持し、FragmentStatePagerdAapter
、切り替わりの度にSaveInstance、破棄、生成される。
実装必須となるメソッドは2つだが、タブのタイトルを返すメソッドも実装できる。
getCount()
はViewPagerのページ数を返す
val fragmentList = listOf<Fragment>(
Tab1PostsFragment.newInstance(),
Tab2PostsFragment.newInstance()
)
override fun getCount(): Int {
return fragmentList.size
}
getItem()
はpositionに応じたFragmentインスタンスを返す
override fun getItem(position: Int): Fragment {
val fragment = fragmentList.get(position)
return fragment
}
getPageTitle()
はpositionに応じたタイトルを返す
override fun getPageTitle(position: Int): CharSequence? {
val tabTitles = listOf<String>(
"まとめブログ", "個人ブログ"
)
return resources.getString( tabTitles[position] )
}
最後にAdapterをセットしたViewPagerをTabLayoutに渡せばViewPagerに連動したタブの制御が可能となる。
viewPager.adapter = object : FragmentPagerAdapter(supportFragmentManager){ ... }
tabLayout.setupWithViewPager(viewPager)
タブのレイアウトにデザインを入れる場合
setupWithViewPager()
後に
tabLayout.setupWithViewPager(viewPager)
Tab tab1 = tabLayout.getTabAt(0);
tab1.setText("Home");
tab1.setIcon(R.drawable.tab1);
val view = layoutInflater.inflate(R.layout.activity_main, null)
tab1.setCustomView(view);
のようにすれば、各タブの属性にアクセスできる。
リンク
リンク