情境
如果要使用 TabLayout 在 Android 早期是很痛苦的,漸漸的有很多優秀的第三方出來支援,包含 Indicater、ViewPager 等等…。
由於太常使用這些元件,因此 Google 這次在 android.support.design 這包 library 內,直接就提供 TabLayout 讓你快速建立好一個 Tab 元件。
程式碼下載
你可以到 GitHub 上面觀看或下載完整的程式碼。
程式碼說明
一開始要使用這個元件,在 Gradle 就要把它 import 進來,這邊的版本號是根據你的 Android SDK 來調整版號,因此你可以根據自己的版本來進行調整。
dependencies {
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
}
接著在 activity_main.xml 內掛上你的 TabLayout,在 TabLayout 的下方放了一個 ViewPager,等下可以在 MainActvitity.java 程式內操作這兩個元件。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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"
tools:context=".MainActivity">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabs"
android:minHeight="?attr/actionBarSize"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@+id/tabs"
app:layout_constraintTop_toBottomOf="@+id/tabs"
app:layout_constraintEnd_toEndOf="@+id/tabs"/>
</androidx.constraintlayout.widget.ConstraintLayout>
ViewPager 會需要一個自定義的 Adapter,這個 Adapter 需要一個佈局,所以我們設計了一個 pager_item.xml 如下方佈局。
- pager_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_centerInParent="true"
android:id="@+id/item_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="" />
</RelativeLayout>
接著我們來看一下 MainActvity.java 這段程式碼,可以看到一開始我們從 xml 取出 TabLayout 以及 ViewPager 的物件。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tabs.addTab(tabs.newTab().setText("Tab 1"))
tabs.addTab(tabs.newTab().setText("Tab 2"))
tabs.addTab(tabs.newTab().setText("Tab 3"))
viewpager.adapter = SamplePagerAdapter()
viewpager.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabs))
tabs.addOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(viewpager))
}
class SamplePagerAdapter: PagerAdapter() {
override fun getCount(): Int {
return 3
}
override fun isViewFromObject(view: View, o: Any): Boolean {
return o === view
}
override fun getPageTitle(position: Int): CharSequence? {
return "Page: Item${position + 1}"
}
override fun instantiateItem(container: ViewGroup, position: Int): Any {
val view = LayoutInflater.from(container.context).inflate(R.layout.pager_item, container, false)
container.addView(view)
view.item_title.text = getPageTitle(position)
return view
}
override fun destroyItem(container: ViewGroup, position: Int, any: Any) {
container.removeView(any as View)
}
}
}
這邊你會發現一個重點,就是當 TabLayout 被點選的時候 下方的 ViewPager 就必須跟著滾動,同理當下方 ViewPager 滾動的時候 上方的 TabLayout 就必須跟著跳動,因此會加入這兩行。
viewpager.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabs))
tabs.setOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(viewpager))
但是你會發現,在 setOnTabSelectedListener API 24 的時候已經被棄用了,取而代之的是 addOnTabSelectedListener,因此你可以看到使用以下的方法,也可以跟 ViewPager 和 TabLayout 的連動綁在一起。
viewpager.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabs))
tabs.addOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(viewpager))
另外還有一種方法就是當你在點選 Tab 頁面的時候,還會額外再進行一些事情,那麼你就可以透過以下的方式來進行切換。
tabs.setOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) {
viewpager.currentItem = tab.position
}
override fun onTabUnselected(tab: TabLayout.Tab) {}
override fun onTabReselected(tab: TabLayout.Tab) {}
})
同樣的這個方法也在 API 24 被棄用了,當然還是有替代方案。
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) {
viewpager.currentItem = tab.position
}
override fun onTabUnselected(tab: TabLayout.Tab) {}
override fun onTabReselected(tab: TabLayout.Tab) {}
})
如此一來就可以很輕鬆的把上下兩個元件的連動綁在一起了,如下圖短短幾行就可以看到很棒的效果。
這邊可以看到滾動翻頁的效果。
這樣就是一個簡單的 TabLayout 操作了。