如何实现屏幕底部图标导航栏跳转至不同Activity?
Hey there! 你说的这个底部图标导航栏,其实是现在Android App里非常流行的底部导航组件,官方早就提供了现成的解决方案,也可以自己自定义来满足特殊需求。我给你详细说说两种实现思路:
这是Google推出的Material Design组件,能帮你快速实现规范的底部导航,自带选中状态切换、图标文字联动等功能,步骤如下:
添加依赖
首先确保你的项目已经引入了Material Design库,在Module级别的build.gradle(现在常用build.gradle.kts)里添加:dependencies { implementation "com.google.android.material:material:1.9.0" // 可以替换为最新版本 }在布局文件中添加组件
在你的主Activity布局里,把BottomNavigationView约束到屏幕底部,比如用ConstraintLayout:<?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" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 主内容区域,比如Fragment容器 --> <FrameLayout android:id="@+id/main_content" android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintBottom_toTopOf="@id/bottom_nav" app:layout_constraintTop_toTopOf="parent"/> <!-- 底部导航栏 --> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/bottom_nav" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" app:layout_constraintBottom_toBottomOf="parent" app:menu="@menu/bottom_nav_menu"/> </androidx.constraintlayout.widget.ConstraintLayout>创建菜单资源文件
在res/menu目录下新建bottom_nav_menu.xml,定义每个导航项的图标和文字:<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/nav_home" android:icon="@drawable/ic_home" android:title="首页"/> <item android:id="@+id/nav_discover" android:icon="@drawable/ic_discover" android:title="发现"/> <item android:id="@+id/nav_profile" android:icon="@drawable/ic_profile" android:title="我的"/> </menu>在Activity中设置跳转逻辑
找到BottomNavigationView,设置选中监听,点击时跳转对应的Activity:class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav) bottomNav.setOnItemSelectedListener { item -> when(item.itemId) { R.id.nav_home -> { startActivity(Intent(this, HomeActivity::class.java)) true } R.id.nav_discover -> { startActivity(Intent(this, DiscoverActivity::class.java)) true } R.id.nav_profile -> { startActivity(Intent(this, ProfileActivity::class.java)) true } else -> false } } } }小技巧:如果不想每次跳转都创建新的Activity实例,可以给Intent添加
FLAG_ACTIVITY_REORDER_TO_FRONT,或者在AndroidManifest里给目标Activity设置launchMode="singleTop"。
如果官方组件的样式满足不了你的设计(比如要自定义图标大小、间距、特殊动画),可以自己动手做一个:
编写布局文件
用LinearLayout或者ConstraintLayout做底部容器,每个导航项用ImageView+TextView的组合:<?xml version="1.0" encoding="utf-8"?> <LinearLayout android:id="@+id/custom_bottom_nav" android:layout_width="match_parent" android:layout_height="60dp" android:background="@color/white" android:orientation="horizontal" android:gravity="center" app:layout_constraintBottom_toBottomOf="parent"> <!-- 首页项 --> <LinearLayout android:id="@+id/nav_home_custom" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical" android:gravity="center" android:clickable="true" android:focusable="true"> <ImageView android:id="@+id/home_icon" android:layout_width="24dp" android:layout_height="24dp" android:src="@drawable/ic_home_selected"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="首页" android:textColor="@color/primary_color"/> </LinearLayout> <!-- 发现项 --> <LinearLayout android:id="@+id/nav_discover_custom" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical" android:gravity="center" android:clickable="true" android:focusable="true"> <ImageView android:id="@+id/discover_icon" android:layout_width="24dp" android:layout_height="24dp" android:src="@drawable/ic_discover_unselected"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="发现" android:textColor="@color/grey"/> </LinearLayout> <!-- 我的项 --> <LinearLayout android:id="@+id/nav_profile_custom" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical" android:gravity="center" android:clickable="true" android:focusable="true"> <ImageView android:id="@+id/profile_icon" android:layout_width="24dp" android:layout_height="24dp" android:src="@drawable/ic_profile_unselected"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="我的" android:textColor="@color/grey"/> </LinearLayout> </LinearLayout>设置点击事件和状态切换
在Activity中给每个项设置点击监听,切换选中状态(图标、文字颜色)并跳转Activity:class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 初始化导航项和控件 val homeNav = findViewById<LinearLayout>(R.id.nav_home_custom) val discoverNav = findViewById<LinearLayout>(R.id.nav_discover_custom) val profileNav = findViewById<LinearLayout>(R.id.nav_profile_custom) val homeIcon = findViewById<ImageView>(R.id.home_icon) val discoverIcon = findViewById<ImageView>(R.id.discover_icon) val profileIcon = findViewById<ImageView>(R.id.profile_icon) val homeText = homeNav.findViewById<TextView>(android.R.id.text1) val discoverText = discoverNav.findViewById<TextView>(android.R.id.text1) val profileText = profileNav.findViewById<TextView>(android.R.id.text1) // 首页点击逻辑 homeNav.setOnClickListener { updateNavState(homeIcon, homeText, true) updateNavState(discoverIcon, discoverText, false) updateNavState(profileIcon, profileText, false) startActivity(Intent(this, HomeActivity::class.java)) } // 发现点击逻辑 discoverNav.setOnClickListener { updateNavState(homeIcon, homeText, false) updateNavState(discoverIcon, discoverText, true) updateNavState(profileIcon, profileText, false) startActivity(Intent(this, DiscoverActivity::class.java)) } // 我的点击逻辑 profileNav.setOnClickListener { updateNavState(homeIcon, homeText, false) updateNavState(discoverIcon, discoverText, false) updateNavState(profileIcon, profileText, true) startActivity(Intent(this, ProfileActivity::class.java)) } } // 封装状态切换方法,减少重复代码 private fun updateNavState(icon: ImageView, text: TextView, isSelected: Boolean) { if (isSelected) { icon.setImageResource(R.drawable.ic_home_selected) // 替换为对应选中图标 text.setTextColor(resources.getColor(R.color.primary_color)) } else { icon.setImageResource(R.drawable.ic_home_unselected) // 替换为对应未选中图标 text.setTextColor(resources.getColor(R.color.grey)) } } }
如果你的App是用Fragment切换页面而非跳转Activity,官方的BottomNavigationView可以配合NavController实现更流畅的页面切换,不过针对你问的Activity跳转需求,上面的代码已经完全够用啦。另外,记得给图标准备选中/未选中两种状态的资源,或者用tint属性动态改色,这样更高效。
内容的提问来源于stack exchange,提问作者Ted pottel

