使用 Kotlin 在 Android 上构建 WhatsApp 克隆版 – 第 1 部分

2025-05-28

使用 Kotlin 在 Android 上构建 WhatsApp 克隆版 – 第 1 部分

过去几年,Android 开发取得了长足的进步。Jetpack组件显著加快了开发速度。在本教程中,我们将使用Kotlin构建一个 WhatsApp 的功能克隆版。构建一个消息应用曾经非常困难;在本教程中,您将在大约 20 分钟内获得一个流畅的聊天体验。本教程的第一部分重点介绍 WhatsApp 的聊天功能,第二部分将介绍音频和视频通话。现在就开始吧!

如果您在本教程中迷失了方向,您可以查看:

最终结果将类似于此:

克隆 WhatsApp Starter Repo

首先克隆WhatsApp Clone Github repo启动分支:

git clone -b starter git@github.com:GetStream/WhatsApp-Clone-Android.git
Enter fullscreen mode Exit fullscreen mode

启动分支设置了一些简单的东西,所以你可以跳过样板:

  • build.gradle文件中的依赖关系
  • 颜色
  • 菜单项
  • 可绘制对象

在Android StudioWhatsApp-Clone-Android打开目录,等待 Gradle 同步完成。在本教程中,您需要使用Pixel 3 / API Level 29 模拟器进行测试。完成设置后,运行应用程序。您现在应该会看到以下空白屏幕:

聊天屏幕空白

设置主屏幕

第一步,我们将创建应用的主屏幕。它看起来如下:

克隆主屏幕的示例

作为一名经验丰富的 Android 开发人员,您会在此屏幕中看到以下几项内容:

在本教程中,我们将遵循 Google 的建议,即使用 1 个 Activity 和多个 Fragment。我们将使用导航组件连接各个 Fragment 。让我们开始吧。

打开activity_main.xml并将TextView标签替换为NavHostFragment

app:navGraph属性告知导航组件使用你的navigation/nav_graph.xml文件进行导航。让我们花点时间回顾一下以下内容nav_graph.xml

注意在导航标签中如何@id/nav_home将 指定为startDestination。这会使导航组件自动加载homeFragment。下一步,我们将使其homeFragment看起来像 WhatsApp 一样。

打开fragment_home.xml并将内容替换为以下内容:

Material UI 包提供TabLayout的 与 相结合,ViewPager2为您提供了 WhatsApp 界面中实用的可滑动标签。FloatingActionButton负责处理创建新对话的 UI。

下一步,打开它,com.example.whatsappclone.ui.home.HomeFragment.kt
你会看到一个空的 fragment 类,里面有一个 TODO 选项。我们先更新一下构造函数,让它指向R.layout.fragment_home布局。更新后的HomeFragment类如下所示:

class HomeFragment : Fragment(R.layout.fragment_home) {
}
Enter fullscreen mode Exit fullscreen mode

这种用于创建 Fragment 的简短语法是由androidx.navigation:navigation-fragment-ktx依赖项启用的。与覆盖 onCreate 方法相比,这是一个不错的改进。运行应用后,你将看到以下 UI:

标签页已可用,但viewPager和工具栏尚未设置。请返回com.example.whatsappclone.ui.home.HomeFragment.kt并更新,使其与以下内容一致:

这段代码看起来很多,但仔细查看一下就会发现其实很简单。这viewPager2需要一个适配器。我们设置了这个适配器,使其emptyFragment为标签页 0、2、3 返回一个 ,ChannelListFragment为标签页 1 返回一个 。

下方标签上的循环getColorStateList处理相机图标的色调。这确保它在未选中时显示为灰色,在选中时显示为白色。

TabLayoutMediator 将viewpager两者与标签页 UI 连接起来。尝试重新运行应用,你会发现它现在看起来更接近 WhatsApp 界面了。工具栏正在渲染,你可以滑动浏览标签页。

频道列表

接下来,我们将渲染频道/对话列表。首先,打开空fragment_channel_list.xml布局并将其替换为以下内容:

我们使用的是ChannelListView,它是 Stream 提供的自定义视图。此视图可以轻松呈现频道列表。

注意:您也可以使用底层 API 客户端构建频道列表视图。(但这需要更多工作,因此本教程中不会涉及此操作)。

接下来ChannelListFragment.kt,你会看到一个空的 fragment。将文件内容替换为以下内容:

以上内容需要注意几点ChannelListFragment。我们正在实例化 Stream 客户端并连接用户。之后,我们channelList使用 配置组件viewModel.setChannelFilter(filter)。在本教程中,我们使用 Stream 提供的示例 API 密钥。请注意,此示例帐户会定期被清除。因此,如果您正在构建生产环境应用,则需要注册以获取您自己的Stream Chat API 密钥

我们还使用现代 Kotlin 语法来获取非常漂亮的 viewModel:

val viewModel: ChannelListViewModel by viewModels()
Enter fullscreen mode Exit fullscreen mode

最后,观察我们如何使用导航组件和 Kotlin 安全参数从频道列表导航到频道。该类HomeFragmentDirections是从 自动生成的nav_graph.xml,并且 Android 知道如何使用 中定义的操作在各个视图之间导航nav_graph.xml。 中的参数标签nav_graph.xml确保类型安全:

是时候运行你的应用程序了。生成的代码应该渲染出如下所示的应用程序:

频道用户界面

你会注意到,点击某个频道时,你会看到一个空白页面。下一步,我们将实现聊天/频道界面。频道 UI 如下所示:

此 UI 由一个MessageListView和一个自定义消息输入框组成。对于消息输入框,我们将使用双向数据绑定

第一步,打开空白处fragment_channel.xml并将内容替换为:

接下来,打开该ChannelFragment.kt文件并将其内容替换为:

package com.example.whatsappclone.ui.channel
Enter fullscreen mode Exit fullscreen mode

上面的代码中需要注意几点。我们使用以下传递的安全参数来实例化一个 Stream 通道对象Navigation Component

var channel = client.channel(args.channelType, args.channelId)
Enter fullscreen mode Exit fullscreen mode

我们正在viewChannel以此为基础创建一个

如果您运行该应用程序,您现在将看到一个带有非常简约的消息输入视图的频道列表:

自定义消息输入视图和数据绑定

在本教程的这一部分,我们将构建消息输入视图。这是 Google 实时数据双向绑定功能的绝佳用例。请注意,如果用户输入了文本,设计会略有变化。第一张图片展示了未输入文本时的布局:

下图展示了用户输入文本时的布局。请注意图标如何从“录制”变为“发送”。此外,相机图标消失了:

打开空view_message_input.xml布局并更新它以匹配此内容:

现在你应该已经很熟悉这个布局的大部分内容了。语音录制图标有一个浮动操作按钮 (FAB),消息输入框和按钮则有一个带背景的约束布局。最令人兴奋的是视图上的这个标签EditText

android:text="@={viewModel.messageInputText}"
Enter fullscreen mode Exit fullscreen mode

@=语法在 viewModel.messageInputText 和编辑文本元素之间创建了双向绑定。只要其中一个项目发生变化,另一个也会随之变化。现在我们已经设置了双向绑定,我们可以使用它来执行以下操作:

  • 将语音图标更改为发送图标
  • 删除相机图标

请注意我们如何使用数据的导入标签导入两种实用方法:

接下来,我们在拍照按钮上应用视图实用方法:

android:visibility="@{TextUtils.isEmpty(viewModel.messageInputText) ? View.VISIBLE : View.GONE}"
Enter fullscreen mode Exit fullscreen mode

这行代码会在用户输入消息时将 Android 可见性设置为“消失”。对于浮动操作按钮,我们像这样切换图标:

android:src="@{TextUtils.isEmpty(viewModel.messageInputText) ? @drawable/ic_mic_black_24dp : @drawable/ic_send_black_24dp}"
Enter fullscreen mode Exit fullscreen mode

现在布局已经准备好了,让我们创建自己的自定义消息输入视图。打开文件com.example.whatsappclone.ui.views.MessageInputView.kt并更新它以匹配以下内容:

接下来,打开fragment_channel.xml并用以下内容替换EditText节点:

https://gist.github.com/nparsons08/df9da66e2dc467587849f716d9f36980

最后,打开ChannelFragment.kt并取消注释此行:

//binding.messageInputView.setViewModel(viewModel!!, this)
Enter fullscreen mode Exit fullscreen mode

现在,当您运行应用时,您将看到一个功能齐全且外观更美观的消息输入框。数据绑定是一个引人注目的概念。您可以在本教程中了解更多信息

频道列表ViewHolder

频道列表看起来已经很不错了。我们看看能不能再升级一下。我们将使用自定义功能viewHolder来定制设计。

打开文件CustomChannelListItemViewHolder.kt并用以下代码替换空的视图持有者:

上面的代码更新了日期格式,使其更接近 WhatsApp 的布局。要使用此功能viewHolder,我们需要创建一个 viewHolderFactory 并将其应用于视图ChannelList

打开文件CustomViewHolderFactory.kt并将其替换为以下代码:

最后一步,我们需要告诉ChannelList视图关于自定义视图持有者的信息。打开ChannelListFragment.kt并取消注释以下行:

// adapter.setViewHolderFactory(CustomViewHolderFactory())
Enter fullscreen mode Exit fullscreen mode

运行应用后,频道列表的日期格式将与 WhatsApp 的格式一致。如果您在本教程的任何时候遇到困难,请注意,您随时可以在GitHub上找到完整的源代码。

自定义 Stream Chat Android SDK

stream-chat-android提供的 Views 和 ViewModels让您可以极其轻松地将聊天功能添加到您的应用程序。根据您的使用情况,您可以使用多种选项来自定义 UI。

  1. 最常见的调整是使用属性来处理。例如,这允许您更改消息颜色。本教程使用此方法来自fragment_channel.xml定义颜色和背景:
<com.getstream.sdk.chat.view.MessageListView
            android:id="@+id/messageList"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_marginBottom="10dp"
            android:background="@color/channel_background"
            app:layout_constraintBottom_toTopOf="@+id/messageInputView"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/toolbar"
            app:streamMessageBackgroundColorMine="@color/message_yours"
            app:streamMessageBackgroundColorTheirs="@color/message_theirs"
            />
Enter fullscreen mode Exit fullscreen mode
  1. 视图允许您指定布局,使您能够进行简单的布局更改。

  2. 对于更显著的 UI 更改,您可以使用ViewHolder。在本教程中,我们使用了该方法来自定义ChannelListView

  3. 或者,您也可以使用低级客户端来构建 UI 或视图模型。在本教程中,我们针对 进行了同样的操作MessageInputView

通过这 4 个级别的自定义,您可以构建任何聊天或消息传递体验。Android聊天文档更详细地介绍了聊天 SDK。

最后的想法

希望你喜欢本教程。如今,构建像 WhatsApp 这样的应用速度真是令人难以置信。Kotlin 和 Android Jetpack 为 Android 生态系统迈出了重要一步。观察并尝试构建像 WhatsApp 这样的成功应用,是学习的好方法。对于真正的应用,你当然希望能够提出一些新颖且与众不同的东西。你可以使用类似的方法来构建任何聊天或消息传递体验。如果你在学习过程中遇到困难或想了解更多信息,以下是一些可以帮助你的链接:

如果您需要支持多个平台,Stream 还提供适用于iOS ChatReact ChatReact Native Chat的教程。

注意:本教程的第 2 部分预计将于 2 月上线,并将解释如何向您的应用添加视频和语音通话。

祝您聊天愉快!

文章来源:https://dev.to/tschellenbach/build-a-whatsapp-clone-on-android-with-kotlin-part-1-mg
PREV
30+ 面向 JavaScript 开发人员的 Github Repos '超棒' JavaScript 列表书籍面试问题算法和数据结构 JavaScript 资源学习 JavaScript
NEXT
你不知道 useEffect