尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Android ToolBar 实现高仿 QQ 消息与电话

Android ToolBar 实现高仿 QQ 消息与电话 一、引言与项目背景在日常 Android 开发中QQ 作为一款国民级社交应用其顶部导航栏设计简洁高效是很多开发者学习的标杆。QQ 的消息与电话界面顶部 ToolBar 不仅展示了标题、状态、联系人信息还集成了视频通话、语音通话、搜索、更多菜单等丰富的交互元素。本文将从零开始手把手带你使用 Android 原生 ToolBar 组件实现一个高仿 QQ 消息与电话界面的完整功能涵盖 UI 布局、自定义 View、动画交互、状态管理、主题适配等核心知识点全文超过 2 万字适合中级及以上 Android 开发者深入阅读。二、ToolBar 基础与环境搭建2.1 ToolBar 与 ActionBar 的关系在 Android 5.0API 21之前应用顶部导航主要使用 ActionBar。ActionBar 功能有限定制性差难以满足复杂 UI 需求。Android 5.0 引入了 ToolBar 组件它本质上是一个 ViewGroup可以像普通 View 一样嵌入到布局文件中支持高度自定义。ToolBar 与 ActionBar 的最大区别在于ToolBar 是 Material Design 体系下的通用组件不强制绑定 Activity 的窗口装饰开发者可以自由添加子 View、自定义样式、控制动画表现。同时ToolBar 天然支持与 CoordinatorLayout、AppBarLayout 等 Material 组件协同工作可以轻松实现折叠、上滑隐藏等高级效果而 ActionBar 几乎无法做到。2.2 引入 Material Design 依赖要使用 ToolBar首先需要在项目中引入 Material Design 库。在 app 模块的 build.gradle 中添加以下依赖dependencies { implementation com.google.android.material:material:1.9.0 implementation androidx.appcompat:appcompat:1.6.1 implementation androidx.core:core-ktx:1.10.1 implementation androidx.constraintlayout:constraintlayout:2.1.4 }确保使用 AndroidX 系列包旧版 support 库已停止维护。ToolBar 类位于 androidx.appcompat.widget.Toolbar 包中。如果项目仍在使用 support 库建议尽快迁移到 AndroidX因为 Google 已停止对 support 库的功能更新和安全维护。2.3 基础 ToolBar 布局文件在 activity_main.xml 中编写一个最基础的 ToolBar 布局?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android xmlns:apphttp://schemas.android.com/apk/res-auto android:layout_widthmatch_parent android:layout_heightmatch_parent android:orientationvertical androidx.appcompat.widget.Toolbar android:idid/toolbar android:layout_widthmatch_parent android:layout_height?attr/actionBarSize android:backgroundcolor/colorPrimary android:elevation4dp android:themestyle/ThemeOverlay.AppCompat.Dark.ActionBar app:popupThemestyle/ThemeOverlay.AppCompat.Light app:titleTextColorandroid:color/white / FrameLayout android:idid/content_frame android:layout_widthmatch_parent android:layout_heightmatch_parent / /LinearLayout在 Activity 中使用 ToolBar 替代默认 ActionBarpublic class MainActivity extends AppCompatActivity { private Toolbar toolbar; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); toolbar findViewById(R.id.toolbar); setSupportActionBar(toolbar); // 可选配置 if (getSupportActionBar() ! null) { getSupportActionBar().setDisplayHomeAsUpEnabled(false); getSupportActionBar().setDisplayShowTitleEnabled(false); } } }由于本文最终要实现高仿 QQ 风格因此我们将默认隐藏 ToolBar 自带的标题和返回键转而使用自定义布局来承载头像、昵称、状态等复杂 UI。2.4 自定义 ToolBar 主题在 styles.xml 中定义 ToolBar 专用主题覆盖标题颜色、字体大小、溢出菜单样式等属性style nameAppTheme.Toolbar parentThemeOverlay.AppCompat.Dark.ActionBar item nameandroid:textColorPrimaryandroid:color/white/item item nameandroid:textColorSecondaryandroid:color/white/item item nameactionMenuTextColorandroid:color/white/item item nametitleTextStylestyle/ToolbarTitleStyle/item /style style nameToolbarTitleStyle item nameandroid:textSize18sp/item item nameandroid:textColorandroid:color/white/item item nameandroid:fontFamilysans-serif-medium/item /style在 app 的全局主题中将 ToolBar 的默认样式替换为上面定义的主题可以保证所有 ToolBar 实例都拥有一致的外观表现。三、高仿 QQ 消息顶部布局实战3.1 分析 QQ 消息界面顶部结构打开 QQ 的消息列表页面我们观察到顶部导航栏的结构从上到下依次为顶部状态栏区域系统状态栏、信号、电量等不属于 ToolBar 本体、标题栏区域左侧显示用户头像加昵称中间显示“消息”或自定义状态文字右侧通常为添加联系人、搜索等图标。在一些版本中中间会显示“消息”二字右侧依次为“”和搜索图标。需要注意的是QQ 的消息页 ToolBar 并不是简单地使用 ToolBar 的 title 和 menu而是采用完全自定义布局的方式。具体做法是在 ToolBar 内部嵌套一个 LinearLayout 或 ConstraintLayout再放置头像 ImageView、昵称 TextView、状态 TextView 以及若干功能图标。这种设计可以让整个标题栏的排版自由度达到最高便于后期修改与扩展。同时QQ 的电话页顶部结构类似但中间区域会显示“电话”或在线状态右侧图标变为通话记录、添加联系人等。本文将分别实现消息页和电话页的 ToolBar并通过 ViewPager 或 TabLayout 实现页签切换。3.2 消息页 ToolBar 自定义布局实现首先创建消息页的 ToolBar 布局文件 layout_toolbar_message.xmlandroidx.appcompat.widget.Toolbar xmlns:androidhttp://schemas.android.com/apk/res/android xmlns:apphttp://schemas.android.com/apk/res-auto android:idid/toolbar_message android:layout_widthmatch_parent android:layout_height?attr/actionBarSize android:backgroundcolor/qq_blue android:elevation4dp LinearLayout android:layout_widthmatch_parent android:layout_heightmatch_parent android:gravitycenter_vertical android:orientationhorizontal de.hdodenhof.circleimageview.CircleImageView android:idid/iv_avatar android:layout_width36dp android:layout_height36dp android:layout_marginStart8dp android:srcdrawable/ic_avatar_default / TextView android:idid/tv_nickname android:layout_width0dp android:layout_heightwrap_content android:layout_marginStart10dp android:layout_weight1 android:ellipsizeend android:maxLines1 android:text我的昵称 android:textColorandroid:color/white android:textSize16sp android:textStylebold / TextView android:idid/tv_status android:layout_widthwrap_content android:layout_heightwrap_content android:layout_marginEnd8dp android:text在线 android:textColorcolor/qq_status_green android:textSize12sp / ImageView android:idid/iv_add android:layout_width24dp android:layout_height24dp android:layout_marginEnd12dp android:srcdrawable/ic_add / ImageView android:idid/iv_search android:layout_width24dp android:layout_height24dp android:layout_marginEnd12dp android:srcdrawable/ic_search / /LinearLayout /androidx.appcompat.widget.Toolbar上述布局使用了 CircleImageView 来实现圆形头像需要依赖implementation de.hdodenhof:circleimageview:3.1.0在 Activity 或 Fragment 中通过下面的方式加载并设置自定义布局Toolbar toolbar findViewById(R.id.toolbar_message); toolbar.setTitle(); // 隐藏默认标题 toolbar.setContentInsetsAbsolute(0, 0); // 清除内边距 // 设置自定义内容 toolbar.addView(getLayoutInflater().inflate(R.layout.layout_toolbar_message, toolbar, false)); // 或者使用 ViewStub 延迟加载以优化性能注意为了完全掌控布局我们清除了 ToolBar 的默认左右内边距否则无法贴边显示头像等内容。同时自定义的 LinearLayout 已经承担了所有内容摆放任务因此不需要再调用 setSupportActionBar 中的标题相关方法。3.3 消息页 ToolBar 交互事件处理为每个按钮绑定点击事件并在代码中处理逻辑ImageView ivAdd toolbar.findViewById(R.id.iv_add); ivAdd.setOnClickListener(v - { // 弹出添加好友、创建群聊等菜单 showAddMenu(v); }); ImageView ivSearch toolbar.findViewById(R.id.iv_search); ivSearch.setOnClickListener(v - { // 跳转到搜索页面或展开搜索栏 navigateToSearch(); }); CircleImageView ivAvatar toolbar.findViewById(R.id.iv_avatar); ivAvatar.setOnClickListener(v - { // 跳转到个人主页或侧边栏 navigateToProfile(); });对于昵称点击可以展示在线状态切换或跳转到设置页面。这些交互可以根据实际需求灵活调整。3.4 搜索展开与更多菜单实现当用户点击搜索图标时我们可以在 ToolBar 内部动态切换为搜索输入框覆盖原有布局实现类似 QQ 的沉浸式搜索效果。实现思路如下布局切换在 ToolBar 内部预先放置两个 FrameLayout其中一个承载默认内容另一个承载搜索栏通过设置 visibility 切换。动画过渡使用 TransitionManager 或自定义动画让搜索栏展开/收缩时更加平滑。键盘控制展开搜索栏时自动弹出软键盘并监听返回键以折叠搜索栏。FrameLayout android:idid/fl_search_container android:layout_widthmatch_parent android:layout_heightmatch_parent android:visibilitygone EditText android:idid/et_search android:layout_widthmatch_parent android:layout_heightmatch_parent android:backgroundandroid:color/transparent android:hint搜索 android:textColorHint#80ffffff android:textColorandroid:color/white android:inputTypetext / ImageView android:idid/iv_close_search android:layout_width24dp android:layout_height24dp android:layout_gravityend|center_vertical android:layout_marginEnd12dp android:srcdrawable/ic_close / /FrameLayout在代码中通过设置 fl_search_container 可见并隐藏默认 LinearLayout实现搜索模式切换。同时处理返回键逻辑在搜索可见时优先折叠搜索栏而非退出页面。四、高仿 QQ 电话顶部布局实战4.1 电话页 ToolBar 结构分析QQ 的电话页通常与消息页并排通过底部导航或顶部 Tab 切换。电话页的 ToolBar 布局类似但中间显示“电话”二字右侧依次为通话记录图标和添加联系人图标。有些版本中还会在标题下方显示“在线”或“可使用 QQ 电话”等提示信息。电话页 ToolBar 同样使用完全自定义布局不再重复基础搭建直接给出核心布局文件和交互实现。4.2 电话页 ToolBar 布局实现LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightmatch_parent android:gravitycenter_vertical android:orientationhorizontal TextView android:idid/tv_title_call android:layout_width0dp android:layout_heightwrap_content android:layout_weight1 android:gravitycenter android:text电话 android:textColorandroid:color/white android:textSize18sp android:textStylebold / ImageView android:idid/iv_call_history android:layout_width24dp android:layout_height24dp android:layout_marginEnd12dp android:srcdrawable/ic_history / ImageView android:idid/iv_add_contact android:layout_width24dp android:layout_height24dp android:layout_marginEnd12dp android:srcdrawable/ic_add_contact / /LinearLayout将该布局 inflate 到电话页的 ToolBar 中即可。交互逻辑类似点击通话记录打开最近通话列表点击添加联系人跳转到联系人选择界面。4.3 电话页状态指示器有时需要在电话页顶部展示一个细条状态栏比如“网络状态良好”或者“正在通话中”。这可以通过在 ToolBar 下方添加一个狭长的 View 或者直接在 ToolBar 内部增加一个窄条布局来实现。例如View android:idid/view_status_bar android:layout_widthmatch_parent android:layout_height4dp android:backgroundcolor/qq_green /在代码中根据网络状态或通话状态动态改变背景颜色和显示隐藏增加用户体验。五、下拉搜索框与更多菜单实现5.1 弹出式更多菜单除了在 ToolBar 右侧直接放置图标外QQ 还常使用弹出菜单PopupMenu来收纳更多操作。例如点击“”按钮弹出包含“加好友/群”、“扫一扫”、“面对面快传”等的菜单列表。使用 PopupMenu 实现private void showAddMenu(View anchor) { PopupMenu popup new PopupMenu(this, anchor, Gravity.END); popup.getMenuInflater().inflate(R.menu.menu_add, popup.getMenu()); popup.setOnMenuItemClickListener(item - { int id item.getItemId(); if (id R.id.action_add_friend) { // 跳转加好友 return true; } else if (id R.id.action_create_group) { // 跳转建群 return true; } return false; }); popup.show(); }菜单文件 res/menu/menu_add.xmlmenu xmlns:androidhttp://schemas.android.com/apk/res/android item android:idid/action_add_friend android:title加好友/群 / item android:idid/action_create_group android:title创建群聊 / item android:idid/action_scan android:title扫一扫 / /menu5.2 下拉搜索框的完整实现前文已经描述了搜索栏的基本布局切换这里补充输入事件处理和搜索历史管理。当用户在搜索框输入文字时可以使用 RxJava 或 LiveData 实现防抖避免频繁触发搜索请求。同时可以保存搜索历史并在搜索栏下方展示通过 RecycleView 实现历史记录列表。代码示例private void setupSearchInput(EditText etSearch) { RxTextView.textChanges(etSearch) .debounce(300, TimeUnit.MILLISECONDS) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::performSearch); }搜索框展开时toolbar 下方的 RecyclerView 可以动态显示搜索结果或历史记录。为了不遮挡内容区域通常会用 FrameLayout 承载主内容将搜索建议列表覆盖在内容之上。六、动画与交互优化6.1 ToolBar 展开与收缩动画借助 AppBarLayout 和 CoordinatorLayout可以实现 ToolBar 跟随列表滑动收起和展开的效果。但 QQ 的消息页 ToolBar 并不支持滑动折叠而是始终固定。本文主要介绍点击搜索时搜索栏的展开动画以及 Tab 切换时 ToolBar 内容的平滑过渡。使用 TransitionManager 简化动画TransitionManager.beginDelayedTransition(toolbar, new Fade()); toolbar.removeAllViews(); toolbar.addView(searchView);6.2 Tab 切换时 ToolBar 平滑切换QQ 消息页和电话页共用同一个 ToolBar 还是分别维护通常可以使用 ViewPager 配合 TabLayoutToolBar 独立于 ViewPager 之外根据当前选中的页面动态切换 ToolBar 的内容。例如viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { Override public void onPageSelected(int position) { switchToolbarContent(position); } });switchToolbarContent 方法内部移除当前 ToolBar 的内容并 inflate 对应的布局文件。为了增加平滑过渡可以使用 android:animateLayoutChangestrue 在 ToolBar 上启用默认布局动画或者自定义内容淡入淡出效果。6.3 图标点击涟漪效果为所有图标 ImageView 设置 background 为 ripple 效果提升触摸反馈。可以使用 ?attr/selectableItemBackgroundBorderless 或自定义 ripple。android:background?attr/selectableItemBackgroundBorderless七、主题适配与多机型兼容7.1 日间/夜间模式适配QQ 支持夜间模式ToolBar 的背景、文字颜色、图标颜色都需要随之变化。利用 Android 的资源限定符和主题属性可以方便地实现。定义 attrs.xmlattr nametoolbarBackground formatcolor / attr nametoolbarTextColor formatcolor /然后在日间和夜间主题中分别赋值ToolBar 布局中使用 ?attr/toolbarBackground 等引用属性即可。图标可以使用 tint 属性动态着色。7.2 刘海屏、挖孔屏适配在全面屏时代ToolBar 的高度和内容布局需要考虑状态栏高度以及刘海区域。可以通过设置 android:fitsSystemWindowstrue 并配合 WindowInsets 来获取系统安全区域手动调整 ToolBar 的 padding 或 margin。toolbar.setOnApplyWindowInsetsListener((v, insets) - { int top insets.getSystemWindowInsetTop(); v.setPadding(v.getPaddingLeft(), top, v.getPaddingRight(), v.getPaddingBottom()); return insets.consumeSystemWindowInsets(); });7.3 多屏幕尺寸适配针对不同屏幕宽度头像大小、图标间距、文字大小可以使用 dimens.xml 中不同限定符的值。对于大屏设备可以适当增大头像和图标尺寸保持视觉协调。八、性能优化与最佳实践8.1 避免过度绘制自定义 ToolBar 内部 View 层级应尽量扁平化避免嵌套过多的布局容器。使用 ConstraintLayout 替代多层 LinearLayout 可以有效减少层级。此外为 ToolBar 设置背景色时不要覆盖不必要的透明区域。8.2 延迟加载与 ViewStub如果 ToolBar 中包含不常用或复杂的子布局如搜索栏、更多菜单可以使用 ViewStub 延迟初始化减少首次绘制时间。ViewStub android:idid/stub_search android:layoutlayout/layout_search_bar android:layout_widthmatch_parent android:layout_heightmatch_parent /仅在需要展开搜索时调用 inflate之后再进行切换。8.3 内存与线程管理在处理图标资源时使用矢量图VectorDrawable以减小 APK 体积并适应不同分辨率。避免在 ToolBar 的频繁刷新过程中创建大量临时对象。对于搜索界面的历史记录 Adapter使用 DiffUtil 高效更新列表。8.4 无障碍与国际化为所有图标添加 contentDescription 属性以支持无障碍服务。文字内容不要硬编码使用 strings.xml 资源便于后期国际化。九、总结与展望本文从 ToolBar 基础开始逐步深入到高仿 QQ 消息与电话界面的完整实现涵盖了自定义布局、搜索展开、主题适配、动画交互、性能优化等多个方面。通过掌握这些技术读者不仅可以实现一个高仿 QQ 风格的应用顶部导航还能举一反三打造出各种复杂自定义 UI。未来随着 Jetpack Compose 的普及ToolBar 的使用方式可能会逐渐被 TopAppBar 和自定义 Composable 替代但本文涉及的自定义布局思想、状态管理、动画处理等能力在任何 UI 框架下都是通用的底层能力。建议读者在理解原生 View 体系的基础上再去学习 Compose会事半功倍。完整项目源码可访问实际开发中可提供 GitHub 链接希望本文能帮助你的项目快速落地 QQ 风格的顶部导航栏。
返回列表