Android多Activity差异化Toolbar复用:替代重复代码的优化方案咨询
完全懂你的痛点!重复写Toolbar的配置代码确实烦,尤其是每个页面只有小差异的时候。咱们可以用自定义Toolbar+基类Activity的方式来解决,完美实现类似PHP动态头部的效果,既统一又能灵活调整。
解决方案:自定义通用Toolbar + 基类Activity
1. 先写通用Toolbar布局
把所有页面共有的元素(比如返回按钮、标题)固定下来,留出可变区域放每个页面独有的控件:
<!-- res/layout/layout_toolbar_common.xml --> <?xml version="1.0" encoding="utf-8"?> <androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/toolbar_common" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:elevation="4dp" app:titleTextColor="@android:color/white"> <!-- 固定左侧返回按钮(默认显示,可隐藏) --> <ImageView android:id="@+id/toolbar_back_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="16dp" android:src="@drawable/ic_back_white" /> <!-- 居中自定义标题(替代系统默认标题) --> <TextView android:id="@+id/toolbar_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textSize="18sp" android:textColor="@android:color/white" android:text="默认标题" /> <!-- 可变容器:放每个页面独有的按钮/视图 --> <LinearLayout android:id="@+id/toolbar_custom_container" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="end" android:orientation="horizontal" android:gravity="center_vertical" android:paddingEnd="16dp"> </LinearLayout> </androidx.appcompat.widget.Toolbar>
2. 封装基类Activity处理通用逻辑
写一个BaseToolbarActivity,把所有重复的Toolbar初始化、点击事件等逻辑都放这里,同时给子类留出自定义的入口:
abstract class BaseToolbarActivity : AppCompatActivity() { protected lateinit var toolbar: Toolbar protected lateinit var customContainer: LinearLayout override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(getLayoutResId()) initToolbar() // 让子类处理自定义差异 setupCustomToolbar() } // 子类必须返回自己的布局ID(布局里要include通用Toolbar) abstract fun getLayoutResId(): Int private fun initToolbar() { toolbar = findViewById(R.id.toolbar_common) customContainer = findViewById(R.id.toolbar_custom_container) setSupportActionBar(toolbar) // 隐藏系统自带标题,用我们的自定义TextView supportActionBar?.setDisplayShowTitleEnabled(false) // 默认返回按钮逻辑,子类可重写 findViewById<ImageView>(R.id.toolbar_back_btn).setOnClickListener { onBackPressedDispatcher.onBackPressed() } } // 子类重写这个方法,实现自己的Toolbar差异 open fun setupCustomToolbar() { // 默认空实现,按需扩展 } // 公共方法:设置标题 protected fun setToolbarTitle(title: String) { findViewById<TextView>(R.id.toolbar_title).text = title } // 公共方法:隐藏返回按钮 protected fun hideBackButton() { findViewById<ImageView>(R.id.toolbar_back_btn).visibility = View.GONE } // 公共方法:向可变区域添加自定义视图 protected fun addCustomView(view: View) { customContainer.addView(view) } }
3. 子类Activity轻松自定义
每个子类Activity只需要继承BaseToolbarActivity,然后在自己的布局里include通用Toolbar,再重写方法处理差异即可:
示例:首页Activity(无返回按钮,有搜索按钮)
首先是布局activity_home.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="match_parent" android:orientation="vertical"> <!-- 引入通用Toolbar --> <include layout="@layout/layout_toolbar_common" /> <!-- 页面其他内容 --> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="首页内容" /> </LinearLayout>
然后是Activity代码:
class HomeActivity : BaseToolbarActivity() { override fun getLayoutResId(): Int { return R.layout.activity_home } override fun setupCustomToolbar() { super.setupCustomToolbar() // 设置标题 setToolbarTitle("首页") // 隐藏返回按钮 hideBackButton() // 添加搜索按钮 val searchBtn = ImageView(this).apply { layoutParams = LinearLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT ) setPadding(16, 0, 0, 0) setImageResource(R.drawable.ic_search_white) setOnClickListener { Toast.makeText(this@HomeActivity, "搜索", Toast.LENGTH_SHORT).show() } } addCustomView(searchBtn) } }
示例:详情页Activity(有返回按钮,有分享按钮)
class DetailActivity : BaseToolbarActivity() { override fun getLayoutResId(): Int { return R.layout.activity_detail } override fun setupCustomToolbar() { super.setupCustomToolbar() setToolbarTitle("详情页") // 添加分享按钮 val shareBtn = ImageView(this).apply { layoutParams = LinearLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT ) setPadding(16, 0, 0, 0) setImageResource(R.drawable.ic_share_white) setOnClickListener { Toast.makeText(this@DetailActivity, "分享", Toast.LENGTH_SHORT).show() } } addCustomView(shareBtn) } }
额外优化建议
- 把Toolbar的样式(比如背景色、标题大小)放到
styles.xml的主题属性里,用?attr/xxx引用,方便全局修改。 - 如果某些页面需要完全不同的Toolbar结构,可以在子类中重写
initToolbar方法,或者直接替换布局中的通用Toolbar(尽量少用,保持风格统一)。 - 可以给基类增加更多公共方法,比如
setToolbarBackground、setTitleTextColor,满足更多自定义需求。
这样一来,所有重复的Toolbar代码都被封装到基类里,子类只需要关注自己的差异化部分,完美解决了代码冗余问题,和你说的PHP动态头部思路完全一致,既统一又灵活!
内容的提问来源于stack exchange,提问作者Someone
相关产品推荐
相关产品推荐

