本文实现上述效果采用的方案为:ViewPager2 + Fragment + TabLayout,总体布局为在一个 Activity 中嵌入 ViewPager2 与 TabLayout 两个控件,再使用 ViewPager2 对 3 个 Fragment进行管理,最后对 TabLayout 中的 item 和对应的 Fragment 之间进行关联。
要想使用 ViewPager2 首先需要在 app\buildgradle
中添加依赖:
dependency {
...
implementation "androidx.viewpager2:viewpager2:1.0.0"
}
然后在需要使用的地方添加使用即可。
本问涉及的字符串内容在 res\values\strings.xml
中,内容如下:
<resources>
<string name="app_name">ViewPager2string>
<string name="hello_blank_fragment">Hello blank fragmentstring>
<string name="lorem_ipsum">Hello blank fragmentstring>
<string name="musicClub">音乐馆string>
<string name="recommend">推荐string>
<string name="live">直播string>
resources>
首先需要准备三个 Fragment 备用,三个 Fragment 的名字为:HomeFragment、MyFragment 与 ScreenSlidePageFragment。因为重点不在 Fragment,因此三者布局类似,此处只展示 ScreenSlidePageFragment 的内容与 xml 文件的内容。
fragment_screen_slide_page.xml
的文件内容:
<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=".ScreenSlidePageFragment">
<TextView
style="?android:textAppearanceMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:lineSpacingMultiplier="1.2"
android:padding="16dp"
android:text="@string/lorem_ipsum" />
FrameLayout>
ScreenSlidePageFragment 的文件内容:
class ScreenSlidePageFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_screen_slide_page, container, false)
}
}
在将上述三个 Fragment 准备好后,就可以开始设置 ViewPager2 了,使用方式如下:本文的启动 Activity 为 ScreenSlidePagerActivity,因此对应的 xml 文件 activity_screen_slide_pager.xml
中的内容为:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
LinearLayout>
ScreenSlidePagerActivity 的具体内容如下:
class ScreenSlidePagerActivity : AppCompatActivity() {
private lateinit var viewPager2: ViewPager2
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_screen_slide_pager)
viewPager2 = findViewById(R.id.pager)
viewPager2.adapter = ScreenSlidePagerAdapter(this)
}
// 此处实现按一下返回键,跳转至左边一个 page
override fun onBackPressed() {
if (viewPager2.currentItem == 0) {
super.onBackPressed()
} else {
viewPager2.currentItem -= 1
}
}
private inner class ScreenSlidePagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) {
// 实现 Fragment 的链表
private val fragmentList: List<Fragment> =
listOf(HomeFragment(), MyFragment(), ScreenSlidePageFragment())
override fun getItemCount() = fragmentList.size
override fun createFragment(position: Int): Fragment = fragmentList[position]
}
}
上述过程首先获取到 ViewPager2 的 id,其次创建了一个内部类作为 ViewPager2 的适配器,由于 ViewPager2 相当于 RacyclerView 的一个扩展版本,因此其适配器的内容也和 RecyclerView 的适配器内容很像。在适配器中创建了一个链表用来管理刚刚创建的 3 个Fragment,getItemCount() 因此返回的就是链表的大小,在 createFragment() 中就返回对应 position 的 Fragment。
此时运行结果如下:
首先修改 activity_screen_slide_pager.xml
中的内容如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
...
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/black" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
style="@style/MyTabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.tabs.TabItem
android:layout_width="0dp"
android:layout_height="match_parent" />
<com.google.android.material.tabs.TabItem
android:layout_width="0dp"
android:layout_height="match_parent" />
<com.google.android.material.tabs.TabItem
android:layout_width="0dp"
android:layout_height="match_parent" />
com.google.android.material.tabs.TabLayout>
LinearLayout>
上述对 TabLayout 的 style 进行了相应的设置,设置的内容在 res\values\themes
中,具体内容如下:
<resources xmlns:tools="http://schemas.android.com/tools">
...
<style name="MyTabLayout" parent="Widget.Design.TabLayout">
- "tabIndicatorHeight"
>0dp
- "tabSelectedTextColor">#1989FA
- "android:textColor">@color/black
- "iconSize">24dp
- "android:textSize">12sp
style>
resources>
然后在 kotlin 代码中对 TabLayout 中的 item 进行具体的设置,修改 ScreenSlidePagerActivity 中内容:
class ScreenSlidePagerActivity : AppCompatActivity() {
private lateinit var viewPager2: ViewPager2
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_screen_slide_pager)
viewPager2 = findViewById(R.id.pager)
viewPager2.adapter = ScreenSlidePagerAdapter(this)
// 获取 TabLayout
val tabLayout = findViewById<TabLayout>(R.id.tabLayout)
// 将 TabLayout 中的 Item 和 viewPager2 中的 Fragment 进行关联
TabLayoutMediator(tabLayout, viewPager2) { tab: TabLayout.Tab, position: Int ->
when (position) {
0 -> {
// 设置 item 的文字内容与 icon
tab.text = getString(R.string.musicClub)
tab.icon = getDrawable(R.drawable.music)
}
1 -> {
tab.text = getString(R.string.recommend)
tab.icon = getDrawable(R.drawable.recommend)
}
2 -> {
tab.text = getString(R.string.live)
tab.icon = getDrawable(R.drawable.live)
}
}
}.attach()
}
...
}
上述首先获取到 TabLayout 的 id,然后使用 TabLayoutMediator() 将 TabLayout 和 ViewPager2 进行关联,该类构造方法接受三个参数,参数类型分别为 TabLayout、ViewPager2 以及 TabLayoutMediator.TabConfigurationStrategy,其中第三个为必须实现的回调接口,以设置新创建的选项卡的文本和样式。此处采用了kotlin的 lambda 表达式。
最后调用该 TabLayoutMediator() 类的 attach() 方法将 TabLayout 和 ViewPager2 链接在一起。(其必须在 ViewPager2 设置适配器后调用。在 TabLayoutMediator 的新实例上调用或在 ViewPager2 的适配器更改时调用。)
在设置 TabItem 的 icon 的时候,icon 的布局应该为一个 selector 类型的文件,如第一个 music 的 xml 文件内容如下:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_music_after" android:state_selected="true" />
<item android:drawable="@drawable/ic_music" android:state_selected="false" />
selector>
做完上述所有步骤后运行便可得到文章开始所实现的效果。
参考:
使用 ViewPager2 在 Fragment 之间滑动 | Android 开发者 | Android Developers (google.cn)
使用 ViewPager2 创建包含标签的滑动视图 | Android 开发者 | Android Developers (google.cn)
从0开始讲解Fragment和ViewPager2的结合使用(2):混合使用_Android小白-CSDN博客