使用 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
启动分支设置了一些简单的东西,所以你可以跳过样板:
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) {
}
这种用于创建 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()
最后,观察我们如何使用导航组件和 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
上面的代码中需要注意几点。我们使用以下传递的安全参数来实例化一个 Stream 通道对象Navigation Component
:
var channel = client.channel(args.channelType, args.channelId)
我们正在viewChannel
以此为基础创建一个
如果您运行该应用程序,您现在将看到一个带有非常简约的消息输入视图的频道列表:
自定义消息输入视图和数据绑定
在本教程的这一部分,我们将构建消息输入视图。这是 Google 实时数据双向绑定功能的绝佳用例。请注意,如果用户输入了文本,设计会略有变化。第一张图片展示了未输入文本时的布局:
下图展示了用户输入文本时的布局。请注意图标如何从“录制”变为“发送”。此外,相机图标消失了:
打开空view_message_input.xml
布局并更新它以匹配此内容:
现在你应该已经很熟悉这个布局的大部分内容了。语音录制图标有一个浮动操作按钮 (FAB),消息输入框和按钮则有一个带背景的约束布局。最令人兴奋的是视图上的这个标签EditText
:
android:text="@={viewModel.messageInputText}"
该@=
语法在 viewModel.messageInputText 和编辑文本元素之间创建了双向绑定。只要其中一个项目发生变化,另一个也会随之变化。现在我们已经设置了双向绑定,我们可以使用它来执行以下操作:
- 将语音图标更改为发送图标
- 删除相机图标
请注意我们如何使用数据的导入标签导入两种实用方法:
接下来,我们在拍照按钮上应用视图实用方法:
android:visibility="@{TextUtils.isEmpty(viewModel.messageInputText) ? View.VISIBLE : View.GONE}"
这行代码会在用户输入消息时将 Android 可见性设置为“消失”。对于浮动操作按钮,我们像这样切换图标:
android:src="@{TextUtils.isEmpty(viewModel.messageInputText) ? @drawable/ic_mic_black_24dp : @drawable/ic_send_black_24dp}"
现在布局已经准备好了,让我们创建自己的自定义消息输入视图。打开文件com.example.whatsappclone.ui.views.MessageInputView.kt
并更新它以匹配以下内容:
接下来,打开fragment_channel.xml
并用以下内容替换EditText
节点:
https://gist.github.com/nparsons08/df9da66e2dc467587849f716d9f36980
最后,打开ChannelFragment.kt
并取消注释此行:
//binding.messageInputView.setViewModel(viewModel!!, this)
现在,当您运行应用时,您将看到一个功能齐全且外观更美观的消息输入框。数据绑定是一个引人注目的概念。您可以在本教程中了解更多信息。
频道列表ViewHolder
频道列表看起来已经很不错了。我们看看能不能再升级一下。我们将使用自定义功能viewHolder
来定制设计。
打开文件CustomChannelListItemViewHolder.kt
并用以下代码替换空的视图持有者:
上面的代码更新了日期格式,使其更接近 WhatsApp 的布局。要使用此功能viewHolder
,我们需要创建一个 viewHolderFactory 并将其应用于视图ChannelList
。
打开文件CustomViewHolderFactory.kt
并将其替换为以下代码:
最后一步,我们需要告诉ChannelList
视图关于自定义视图持有者的信息。打开ChannelListFragment.kt
并取消注释以下行:
// adapter.setViewHolderFactory(CustomViewHolderFactory())
运行应用后,频道列表的日期格式将与 WhatsApp 的格式一致。如果您在本教程的任何时候遇到困难,请注意,您随时可以在GitHub上找到完整的源代码。
自定义 Stream Chat Android SDK
stream-chat-android提供的 Views 和 ViewModels让您可以极其轻松地将聊天功能添加到您的应用程序。根据您的使用情况,您可以使用多种选项来自定义 UI。
- 最常见的调整是使用属性来处理。例如,这允许您更改消息颜色。本教程使用此方法来自
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"
/>
-
视图允许您指定布局,使您能够进行简单的布局更改。
-
对于更显著的 UI 更改,您可以使用
ViewHolder
。在本教程中,我们使用了该方法来自定义ChannelListView
。 -
或者,您也可以使用低级客户端来构建 UI 或视图模型。在本教程中,我们针对 进行了同样的操作
MessageInputView
。
通过这 4 个级别的自定义,您可以构建任何聊天或消息传递体验。Android聊天文档更详细地介绍了聊天 SDK。
最后的想法
希望你喜欢本教程。如今,构建像 WhatsApp 这样的应用速度真是令人难以置信。Kotlin 和 Android Jetpack 为 Android 生态系统迈出了重要一步。观察并尝试构建像 WhatsApp 这样的成功应用,是学习的好方法。对于真正的应用,你当然希望能够提出一些新颖且与众不同的东西。你可以使用类似的方法来构建任何聊天或消息传递体验。如果你在学习过程中遇到困难或想了解更多信息,以下是一些可以帮助你的链接:
如果您需要支持多个平台,Stream 还提供适用于iOS Chat、React Chat和React Native Chat的教程。
注意:本教程的第 2 部分预计将于 2 月上线,并将解释如何向您的应用添加视频和语音通话。
祝您聊天愉快!
文章来源:https://dev.to/tschellenbach/build-a-whatsapp-clone-on-android-with-kotlin-part-1-mg