BottomBar源码解析:核心类BottomBar与BottomBarTab工作原理
在Android应用开发中,底部导航栏(Bottom Navigation Bar)是提升用户体验的关键组件。本文将深入解析BottomBar库中两个核心类——BottomBar与BottomBarTab的工作原理,帮助开发者理解其设计思想与实现细节。通过本文,你将掌握底部导航栏的初始化流程、标签切换机制及动画效果实现。
1. 整体架构与核心类关系
BottomBar库采用组合模式设计,BottomBar作为容器管理多个BottomBarTab标签项。两者通过观察者模式实现交互,当用户点击标签时,BottomBar协调状态更新与UI变化。
核心文件路径:
- BottomBar.java - 导航栏容器实现
- BottomBarTab.java - 标签项组件
2. BottomBar初始化流程
BottomBar的初始化遵循Android自定义视图规范,通过init()方法完成属性解析、视图创建和标签加载。
2.1 属性解析与配置
在init()方法中,通过populateAttributes()解析XML属性,包括标签资源、颜色配置和行为模式:
private void populateAttributes(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.BottomBar, defStyleAttr, defStyleRes);
try {
tabXmlResource = ta.getResourceId(R.styleable.BottomBar_bb_tabXmlResource, 0);
behaviors = ta.getInteger(R.styleable.BottomBar_bb_behavior, BEHAVIOR_NONE);
inActiveTabColor = ta.getColor(R.styleable.BottomBar_bb_inActiveTabColor, defaultInActiveColor);
// 其他属性解析...
} finally {
ta.recycle();
}
}
2.2 视图结构创建
initializeViews()方法加载布局资源并初始化容器:
private void initializeViews() {
View rootView = inflate(getContext(),
isTabletMode ? R.layout.bb_bottom_bar_item_container_tablet :
R.layout.bb_bottom_bar_item_container, this);
tabContainer = (ViewGroup) rootView.findViewById(R.id.bb_bottom_bar_item_container);
// 阴影和背景初始化...
}
布局文件路径:bb_bottom_bar_item_container.xml
2.3 标签加载与配置
通过setItems()方法从XML资源加载标签配置,使用TabParser解析并创建BottomBarTab实例:
public void setItems(@XmlRes int xmlRes) {
TabParser parser = new TabParser(getContext(), defaultTabConfig, xmlRes);
updateItems(parser.parseTabs()); // 解析并更新标签
}
示例标签配置文件:bottombar_tabs_three.xml
3. BottomBarTab实现细节
BottomBarTab封装了标签的视觉状态和交互逻辑,支持选中/未选中状态切换及动画效果。
3.1 状态管理
标签通过select()和deselect()方法切换状态,内部处理颜色、大小和透明度变化:
public void select(boolean animate) {
isActive = true;
if (animate) {
animateIcon(activeAlpha, ACTIVE_SHIFTING_TITLELESS_ICON_SCALE);
animateTitle(sixDps, ACTIVE_TITLE_SCALE, activeAlpha);
animateColors(inActiveColor, activeColor);
} else {
setColors(activeColor);
setAlphas(activeAlpha);
// 直接设置属性...
}
}
3.2 动画实现
标签切换动画通过属性动画实现,包括图标缩放、标题大小变化和颜色过渡:
private void animateColors(int fromColor, int toColor) {
ValueAnimator anim = ValueAnimator.ofInt(fromColor, toColor);
anim.setEvaluator(new ArgbEvaluator());
anim.addUpdateListener(animator -> {
int color = (int) animator.getAnimatedValue();
iconView.setColorFilter(color);
titleView.setTextColor(color);
});
anim.setDuration(150).start();
}
3.3 徽章功能
支持消息徽章显示,通过setBadgeCount()方法管理:
public void setBadgeCount(int count) {
if (count <= 0) {
badge.removeFromTab(this);
return;
}
if (badge == null) {
badge = new BottomBarBadge(getContext());
badge.attachToTab(this, badgeBackgroundColor);
}
badge.setCount(count);
}
4. 交互流程与事件处理
4.1 点击事件分发
BottomBar实现View.OnClickListener接口,将点击事件转换为标签选择逻辑:
@Override
public void onClick(View v) {
int tabPosition = findPositionForTabWithId(v.getId());
if (tabPosition == currentTabPosition) {
onTabReselectListener.onTabReSelected(currentTabPosition);
return;
}
selectTabAtPosition(tabPosition); // 切换标签
}
4.2 监听器模式
通过OnTabSelectListener接口通知外部标签变化:
public void setOnTabSelectListener(OnTabSelectListener listener) {
this.onTabSelectListener = listener;
}
private void updateSelectedTab(int newPosition) {
int oldPosition = currentTabPosition;
currentTabPosition = newPosition;
if (onTabSelectListener != null) {
onTabSelectListener.onTabSelected(newPosition);
}
}
5. 行为模式与样式定制
5.1 内置行为模式
BottomBar支持多种行为模式,通过behaviors属性组合实现:
private static final int BEHAVIOR_NONE = 0;
private static final int BEHAVIOR_SHIFTING = 1; // 移动动画效果
private static final int BEHAVIOR_SHY = 2; // 滚动时隐藏
private static final int BEHAVIOR_ICONS_ONLY = 8; // 仅显示图标
5.2 样式定制
通过XML属性或代码设置自定义样式:
<com.roughike.bottombar.BottomBar
android:id="@+id/bottomBar"
android:layout_width="match_parent"
android:layout_height="56dp"
app:bb_activeTabColor="@color/colorPrimary"
app:bb_inActiveTabColor="@color/grey"
app:bb_tabXmlResource="@xml/bottombar_tabs" />
6. 实际应用示例
6.1 基础用法
在Activity中初始化BottomBar:
BottomBar bottomBar = (BottomBar) findViewById(R.id.bottomBar);
bottomBar.setOnTabSelectListener(tabId -> {
if (tabId == R.id.tab_recents) {
// 切换到最近页面
}
});
6.2 自定义标签布局
通过重写布局文件自定义标签样式:
<!-- 自定义标签布局 -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:id="@+id/bb_bottom_bar_icon"
android:layout_width="24dp"
android:layout_height="24dp"/>
<TextView
android:id="@+id/bb_bottom_bar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"/>
</merge>
7. 性能优化与最佳实践
- 避免过度绘制:通过
setWillNotDraw(false)优化绘制流程 - 复用动画实例:缓存ValueAnimator对象减少创建开销
- 延迟加载:非可见标签可延迟初始化资源
- 测试关键路径:重点测试BottomBarTest.java中的边界情况
8. 总结与扩展
BottomBar库通过优雅的设计模式实现了灵活可定制的底部导航栏。核心优势包括:
- 模块化设计,易于扩展新行为模式
- 高效动画实现,保证60fps流畅度
- 完整的状态管理,支持配置保存与恢复
扩展方向:
- 支持横向滚动的多标签模式
- 添加自定义过渡动画接口
- 集成Jetpack Navigation组件
掌握这些核心原理后,开发者可以根据需求定制更复杂的导航交互,或贡献新功能到项目仓库。
提示:实际开发中建议参考示例代码中的实现方式,特别是MainActivity.java的最佳实践。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考




