ViewPager2 + Fragment + TabLayout 的使用实现类似微信的底部导航栏(kotlin)

文章目录

    • 效果
    • 实现方案
      • ViewPager2 + Fragment 的使用
      • TabLayout 的使用

效果

实现方案

ViewPager2 + Fragment 的使用

本文实现上述效果采用的方案为: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。

此时运行结果如下:

TabLayout 的使用

首先修改 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博客

你可能感兴趣的:(Android,android)