早在2019年11月20日,ViewPager2
就发布了正式版本。今天来使用ViewPager2
和BottomNavigationView
完成一个首页Demo.
准备依赖
1 2
| implementation 'com.google.android.material:material:1.1.0' implementation "androidx.viewpager2:viewpager2:1.0.0"
|
开始干活
布局
先来完成主页面的布局,上端是一个ViewPager2,底部是一个BottomNavigationView。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <?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">
<androidx.viewpager2.widget.ViewPager2 android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/bottomNavigationView" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#D1D1D1" app:itemBackground="@null" app:itemTextColor="@drawable/bottom_navigation_selector" app:labelVisibilityMode="labeled" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:menu="@menu/bottom_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
|
BottomNavigationView
1 2 3 4 5 6 7 8 9 10 11 12
| <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/bottomNavigationView" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#D1D1D1" app:itemBackground="@null" app:itemTextColor="@drawable/bottom_navigation_selector" app:labelVisibilityMode="labeled" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:menu="@menu/bottom_menu" />
|
app:itemBackground="@null"
设置为@null
是为了禁止点击时的水波纹效果。
app:labelVisibilityMode="labeled"
设置为labeled
是为了让底部的图标和文字始终都可以显示出来。
app:itemTextColor="@drawable/bottom_navigation_selector"
设置底部按钮被选中时的文字颜色,这里使用选择器来设置
app:menu="@menu/bottom_menu"
使用菜单配置底部按钮
首先设置底部按钮被选中时的文字颜色,bottom_navigation_selector
选择器如下。
1 2 3 4 5
| <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_checked="true" android:color="@color/tab_checked"/> <item android:state_checked="false" android:color="@color/tab_unchecked"/> </selector>
|
接下来新建一个menu.xml
文件,完成menu
。由于底部按钮也需要根据点击而变换,所以在设置icon
的时候,也使用了选择器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?xml version="1.0" encoding="utf-8"?> <menu xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu1" android:icon="@drawable/bottom_navigation_icon_selector1" android:title="菜单1" /> <item android:id="@+id/menu2" android:icon="@drawable/bottom_navigation_icon_selector2" android:title="菜单2" /> <item android:id="@+id/menu3" android:icon="@drawable/bottom_navigation_icon_selector3" android:title="菜单3" /> <item android:id="@+id/menu4" android:icon="@drawable/bottom_navigation_icon_selector4" android:title="菜单4" /> </menu>
|
1 2 3 4 5 6 7
| <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/ic_auto_checked" android:state_checked="true" /> <item android:drawable="@drawable/ic_auto" android:state_checkable="false" /> </selector>
|
只是这样仍不能在点击的时候切换图片,还需要在代码中进行设置。
1 2
| bottomNavigationView.itemIconTintList = null
|
现在BottomNavigationView
就基本完成了,但是仔细看的话,会发现在选中某一个按钮时,对应的字体会从12sp
变大到14sp
。 为了让字体大小不发生变化,可以重写values中的属性,新建一个values.xml, 重写属性。
1 2 3 4 5 6
| <?xml version="1.0" encoding="utf-8"?> <resources>
<dimen name="design_bottom_navigation_active_text_size">12sp</dimen> <dimen name="design_bottom_navigation_text_size">12sp</dimen> </resources>
|
ViewPager2
的使用方法就比BottomNavigationView
简单的多了。当ViewPager2中存放的是Fragment的时候,适配器需要继承FragmentStateAdapter
。
1 2 3 4 5 6 7 8 9 10 11
| class MyFragmentPagerAdapter(fragmentActivity: FragmentActivity, private val mFragments: List<Fragment> ) : FragmentStateAdapter(fragmentActivity) { override fun createFragment(position: Int): Fragment { return mFragments[position] }
override fun getItemCount(): Int { return mFragments.size }
}
|
然后给ViewPager2设置适配器。
1 2 3 4 5 6
| val mFragments = ArrayList<Fragment>() mFragments.add(BlankFragment1()) mFragments.add(BlankFragment2()) mFragments.add(BlankFragment3()) mFragments.add(BlankFragment4()) viewpager.adapter = MyFragmentPagerAdapter(this, mFragments)
|
目前BottomNavigationView
和ViewPager2
都可以单独使用,但是正常的项目中,需要在滑动ViewPager
的时候触发BottomNavigationView
的菜单切换,在点击切换菜单的时候ViewPager2
能够自动切换Fragment
。为了实现这个功能,需要分别设置监听操作。
点击BottomNavigationView的时候,自动切换Fragment。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| bottomNavigationView.setOnNavigationItemSelectedListener { when (it.itemId) { R.id.menu1 -> { viewpager.currentItem = 0 } R.id.menu2 -> { viewpager.currentItem = 1 } R.id.menu3 -> { viewpager.currentItem = 2 } R.id.menu4 -> { viewpager.currentItem = 3 } } return@setOnNavigationItemSelectedListener false }
|
滑动切换Fragment的时候,自动切换底部菜单
ViewPager2
修改的监听Selected
的方法,改为了registerOnPageChangeCallback
和unregisterOnPageChangeCallback
。那么就需要实现一个MyPageChangeCallback
去继承抽象类ViewPager2.OnPageChangeCallback
。
1 2 3 4 5 6 7 8
| class MyPageChangeCallback(private val bottomNavigationView: BottomNavigationView) : ViewPager2.OnPageChangeCallback() { override fun onPageSelected(position: Int) { super.onPageSelected(position) Log.d(TAG, "$position") bottomNavigationView.menu.getItem(position).isChecked = true } }
|
然后在对应的生命周期中去注册和取消监听。
1 2 3 4 5 6 7 8 9 10 11
| override fun onCreate(savedInstanceState: Bundle?) { ··· myPageChangeCallback = MyPageChangeCallback(bottomNavigationView) viewpager.registerOnPageChangeCallback(myPageChangeCallback) ··· }
override fun onDestroy() { super.onDestroy() viewpager.unregisterOnPageChangeCallback(myPageChangeCallback) }
|