1. 在 Android 项目中引用 JitPack 库
AGP 8.+ 根目录的 settings.gradle
dependencyResolutionManagement {
...
repositories {
...
maven { url 'https://jitpack.io' }
}
}
AGP 8.+ 根目录如果是 settings.gradle.kts 文件
dependencyResolutionManagement {
...
repositories {
...
maven { url = uri("https://jitpack.io") }
}
}
AGP 8.- 根目录的 build.gradle
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
2. 添加依赖
在APP目录中的 build.gradle
implementation("com.github.angcyo.DslTablayout:TabLayout:3.5.3")
implementation("com.github.angcyo.DslTablayout:ViewPager2Delegate:3.5.3")
3. 布局 activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".dsltablayout.BottomNavActivity">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#D5D6D6"/>
<!-- app:tab_default_index="0" 默认选中第 0 个 tab,默认选中的索引值-->
<!-- app:tab_item_is_equ_width="true" 让所有的 tab 平分宽度,Item等宽-->
<!-- app:tab_select_color="#DD0000" 选中当前 tab 时,tab 里文本的颜色 -->
<!-- app:tab_text_view_id="@id/content" 要放入的 TextView 的 id,
为 tab_item.xml 里的 id 为 content 的TextView -->
<com.angcyo.tablayout.DslTabLayout
android:id="@+id/dsl_tab_layout"
android:layout_width="match_parent"
android:layout_height="50dp"
app:tab_default_index="0"
app:tab_convex_background="@color/white"
app:tab_item_is_equ_width="true"
app:tab_select_color="#DD0000"
app:tab_text_view_id="@id/content"
/>
</LinearLayout>
4. 底部 tab_item.xml 布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:id="@+id/icon"
android:layout_width="23dp"
android:layout_height="23dp"
android:src="@drawable/selector_tab_video"/>
<TextView
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:text="发现"/>
</LinearLayout>
5. 每个底部 tab 对应的 fragment
a. DiscoveryFragment
class DiscoveryFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_discovery, container, false)
}
companion object {
fun newInstance(): DiscoveryFragment{
val args = Bundle()
val fragment = DiscoveryFragment()
fragment.arguments = args
return fragment
}
}
}
b. fragment_discovery.xml
<?xml version="1.0" encoding="utf-8"?>
<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=".fragment.DiscoveryFragment">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:text="发现界面"
android:layout_gravity="center"/>
</FrameLayout>
其它三个 Fragment(VideoFragment,CategoryFragment,MeFragment)类似。
6. Adapter
class BottomTabAdapter(fragmentActivity : FragmentActivity, private val count : Int)
: FragmentStateAdapter(fragmentActivity) {
override fun getItemCount(): Int {
return count
}
/**
* position 是每个 Fragment 对应的下标
*/
override fun createFragment(position: Int): Fragment {
return when(position){
0 -> DiscoveryFragment.newInstance()
1 -> VideoFragment.newInstance()
2 -> CategoryFragment.newInstance()
else -> MeFragment.newInstance()
}
}
}
7. MainActivity.kt。填充Fragment 和 TabLayout,实现底部导航
在APP目录中的 build.gradle 的 android 下添加 ViewBinding 的使用
android {
...
viewBinding{
enable=true
}
}
class MainActivity : AppCompatActivity() {
private lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// TODO 1初始化底部按钮(tab_item)并添加到 dslTabLayout
for (i in bottomItemTitle.indices){
//TODO TabItemBinding.inflate(layoutInflater)) 通过 ViewBinding 的方式,拿到 tab_item.xml 布局
TabItemBinding.inflate(layoutInflater).apply {
content.text = bottomItemTitle[i]
icon.setImageResource(bottomItemIcon[i])
// 将当前添加了 icon 和 content 的 tab_item 添加到 TabLayout 中
binding.dslTabLayout.addView(root)
}
}
// TODO 2ViewPager + Fragment
binding.viewPager.offscreenPageLimit = bottomItemTitle.size
binding.viewPager.adapter = BottomTabAdapter(this, bottomItemTitle.size)
// TODO 3将 ViewPager 中的 Fragment 与 底部的 Tab 绑定
ViewPager2Delegate.install(binding.viewPager, binding.dslTabLayout, false)
}
companion object{
// TODO 底部 item 的标题
private val bottomItemTitle = listOf(
"发现",
"视频",
"分类",
"我的"
)
// TODO 底部 item 的图标
private val bottomItemIcon = listOf(
R.drawable.selector_tab_discovery,
R.drawable.selector_tab_video,
R.drawable.selector_tab_category,
R.drawable.selector_tab_me
)
}
}
完整项目
链接 DslTabLayout+ViewPager2+Fragment 实现底部导航栏
提取码:ei9o
如果向想通过Android原生的 BottomNavigationView+Viewpager2+Fragment 实现底部导航栏,可以看这一篇帖子 Android---简易的底部导航栏
DslDslTabLayout 官网 : https://github.com/angcyo/DslTabLayout