harmony-chatroom 自研纯血鸿蒙OS Next 5.0聊天APP实战案例

本文涉及的产品
函数计算FC,每月15万CU 3个月
任务调度 XXL-JOB 版免费试用,400 元额度,开发版规格
应用实时监控服务-可观测链路OpenTelemetry版,每月50GB免费额度
简介: HarmonyOS-Chat是一个基于纯血鸿蒙OS Next5.0 API12实战开发的聊天应用程序。这个项目使用了ArkUI和ArkTS技术栈,实现了类似微信的消息UI布局、输入框光标处插入文字、emoji表情图片/GIF动图、图片预览、红包、语音/位置UI、长按语音面板等功能。

历经一个多月潜心研发,重磅原创新作原生鸿蒙harmonyos-chat聊天室项目完成了

未标题-a.png

HarmonyOS-Chat基于纯血鸿蒙OS Next5.0 API12实战开发的聊天应用程序,类似微信的UI界面和功能,提供了包括聊天、通讯录、我、朋友圈等模块。


p1.gif

p2.gif


ArkUI和ArkTS

ArkUI是华为鸿蒙操作系统提供的UI框架,它允许开发者创建丰富的用户界面。ArkTS则是鸿蒙操作系统的一种脚本语言,类似于JavaScript,用于编写ArkUI的应用程序逻辑。


未标题-3.png

p3.gif

arkui实现了下拉刷新、长按菜单,朋友圈等功能。

p3-2.gif

项目结构目录

HarmonyOS-Chat项目的框架结构是基于DevEco Studio 5.0.3.906编码工具构建的。

360截图20241118123651702.png


页面json文件。

df54138f7f1be6d6a7775b64705153d9_1289798-20241119111326298-202389965.png


harmonyos自定义导航条组件

image.png


ffc096406a1fdfa2b1743de6d0217661_1289798-20241119103438252-506834007.png


059e369873a0e442eca9b5de11b3c0b5_1289798-20241031124859083-39238132.png

支持如下参数配置:

@Component
export struct HMNavBar {
  // 是否隐藏左侧的返回键
  @Prop hideBackButton: boolean
  // 标题(支持字符串|自定义组件)
  @BuilderParam title: ResourceStr | CustomBuilder = BuilderFunction
  // 副标题
  @BuilderParam subtitle: ResourceStr | CustomBuilder = BuilderFunction
  // 返回键图标
  @Prop backButtonIcon: Resource | undefined = $r('sys.symbol.chevron_left')
  // 返回键标题
  @Prop backButtonTitle: ResourceStr
  // 背景色
  @Prop bgColor: ResourceColor = $r('sys.color.background_primary')
  // 渐变背景色
  @Prop bgLinearGradient: LinearGradient
  // 图片背景
  @Prop bgImage: ResourceStr | PixelMap
  // 标题颜色
  @Prop fontColor: ResourceColor
  // 标题是否居中
  @Prop centerTitle: boolean
  // 右侧按钮区域
  @BuilderParam actions: Array<ActionMenuItem> | CustomBuilder = BuilderFunction
  // 导航条高度
  @Prop navbarHeight: number = 56

  // ...
}

调用方式:

HMNavBar({
  backButtonIcon: $r('sys.symbol.arrow_left'),
  title: '鸿蒙自定义导航栏',
  subtitle: 'HarmonyOS Next 5.0自定义导航栏',
})
// 自定义渐变背景、背景图片、右侧操作区
HMNavBar({
  hideBackButton: true,
  title: 'HarmonyOS',
  subtitle: 'harmonyos next 5.0 api 12',
  bgLinearGradient: {
    angle: 135,
    colors: [['#42d392 ',0.2], ['#647eff',1]]
  },
  // bgImage: 'pages/assets/nav_bg.png',
  // bgImage: 'https://developer.huawei.com/allianceCmsResource/resource/HUAWEI_Developer_VUE/images/1025-pc-banner.jpeg',
  fontColor: '#fff',
  actions: [
    {
      icon: 'https://developer.huawei.com/allianceCmsResource/resource/HUAWEI_Developer_VUE/images/yuanfuwuicon.png',
      action: () => promptAction.showToast({ message: "show toast index 1" })
    },
    {
      icon: 'https://developer.huawei.com/allianceCmsResource/resource/HUAWEI_Developer_VUE/images/0620logo4.png',
      action: () => promptAction.showToast({ message: "show toast index 2" })
    },
    {
      icon: $r('sys.symbol.person_crop_circle_fill_1'),
      action: () => promptAction.showToast({ message: "show toast index 3" })
    }
  ],
  navbarHeight: 70
})

鸿蒙arkui实现登录/倒计时验证

p0.gif

/**
 * 登录模板
 * @author andy
 */

import { router, promptAction } from '@kit.ArkUI'

@Entry
@Component
struct Login {
  @State name: string = ''
  @State pwd: string = ''

  // 提交
  handleSubmit() {
    if(this.name === '' || this.pwd === '') {
      promptAction.showToast({ message: '账号或密码不能为空' })
    }else {
      // 登录接口逻辑...
      
      promptAction.showToast({ message: '登录成功' })
      setTimeout(() => {
        router.replaceUrl({ url: 'pages/Index' })
      }, 2000)
    }
  }

  build() {
    Column() {
      Column({space: 10}) {
        Image('pages/assets/images/logo.png').height(50).width(50)
        Text('HarmonyOS-Chat').fontSize(18).fontColor('#0a59f7')
      }
      .margin({top: 50})
      Column({space: 15}) {
        TextInput({placeholder: '请输入账号'})
          .onChange((value) => {
            this.name = value
          })
        TextInput({placeholder: '请输入密码'}).type(InputType.Password)
          .onChange((value) => {
            this.pwd = value
          })
        Button('登录').height(45).width('100%')
          .linearGradient({ angle: 135, colors: [['#0a59f7', 0.1], ['#07c160', 1]] })
          .onClick(() => {
            this.handleSubmit()
          })
      }
      .margin({top: 30})
      .width('80%')
      Row({space: 15}) {
        Text('忘记密码').fontSize(14).opacity(0.5)
        Text('注册账号').fontSize(14).opacity(0.5)
          .onClick(() => {
            router.pushUrl({url: 'pages/views/auth/Register'})
          })
      }
      .margin({top: 20})
    }
    .height('100%')
    .width('100%')
    .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
  }
}

827ca3f17870dd64d47385a5b880e2a7_1289798-20241119113748951-657529179.png

Stack({alignContent: Alignment.End}) {
  TextInput({placeholder: '验证码'})
    .onChange((value) => {
      this.code = value
    })
  Button(`${this.codeText}`).enabled(!this.disabled).controlSize(ControlSize.SMALL).margin({right: 5})
    .onClick(() => {
      this.handleVCode()
    })
}

arkui实现60s倒计时

// 验证码参数
@State codeText: string = '获取验证码'
@State disabled: boolean = false
@State time: number = 60

// 获取验证码
handleVCode() {
  if(this.tel === '') {
    promptAction.showToast({ message: '请输入手机号' })
  }else if(!checkMobile(this.tel)) {
    promptAction.showToast({ message: '手机号格式错误' })
  }else {
    const timer = setInterval(() => {
      if(this.time > 0) {
        this.disabled = true
        this.codeText = `获取验证码(${this.time--})`
      }else {
        clearInterval(timer)
        this.codeText = '获取验证码'
        this.time = 5
        this.disabled = false
      }
    }, 1000)
  }
}

鸿蒙arkui实现下拉刷新/长按菜单

00cf7d864fd4985c00ce2972a2daee85_1289798-20241119115109602-1001433050.png

Refresh({
  refreshing: $$this.isRefreshing,
  builder: this.customRefreshTips
}) {
  List() {
    ForEach(this.queryData, (item: RecordArray) => {
      ListItem() {
        // ...
      }
      .stateStyles({pressed: this.pressedStyles, normal: this.normalStyles})
      .bindContextMenu(this.customCtxMenu, ResponseType.LongPress)
      .onClick(() => {
        // ...
      })
    }, (item: RecordArray) => item.cid.toString())
  }
  .height('100%')
  .width('100%')
  .backgroundColor('#fff')
  .divider({ strokeWidth: 1, color: '#f5f5f5', startMargin: 70, endMargin: 0 })
  .scrollBar(BarState.Off)
}
.pullToRefresh(true)
.refreshOffset(64)
// 当前刷新状态变更时触发回调
.onStateChange((refreshStatus: RefreshStatus) => {
  console.info('Refresh onStatueChange state is ' + refreshStatus)
  this.refreshStatus = refreshStatus
})
// 进入刷新状态时触发回调
.onRefreshing(() => {
  console.log('onRefreshing...')
  setTimeout(() => {
    this.isRefreshing = false
  }, 2000)
})

自定义下拉提示。

@State isRefreshing: boolean = false
@State refreshStatus: number = 1

// 自定义刷新tips
@Builder customRefreshTips() {
  Stack() {
    Row() {
      if(this.refreshStatus == 1) {
        SymbolGlyph($r('sys.symbol.arrow_down')).fontSize(24)
      }else if(this.refreshStatus == 2) {
        SymbolGlyph($r('sys.symbol.arrow_up')).fontSize(24)
      }else if(this.refreshStatus == 3) {
        LoadingProgress().height(24)
      }else if(this.refreshStatus == 4) {
        SymbolGlyph($r('sys.symbol.checkmark')).fontSize(24)
      }
      Text(`${
        this.refreshStatus == 1 ? '下拉刷新' :
          this.refreshStatus == 2 ? '释放更新' :
            this.refreshStatus == 3 ? '加载中...' :
              this.refreshStatus == 4 ? '完成' : ''
      }`).fontSize(16).margin({left:10})
    }
    .alignItems(VerticalAlign.Center)
  }
  .align(Alignment.Center)
  .clip(true)
  .constraintSize({minHeight:32})
  .width('100%')
}

53ed82dfd0d8bc4bdfb0d5f84848ac41_1289798-20241119115230213-1785508169.png

40bf4bafa8a5de2cbd5880f81356e67e_1289798-20241119115302037-837203237.png

Image($r('app.media.plus')).height(24).width(24)
  .bindMenu([
    {
      icon: $r('app.media.message_on_message'),
      value:'发起群聊',
      action: () => {}
    },
    {
      icon: $r('app.media.person_badge_plus'),
      value:'添加朋友',
      action: () => router.pushUrl({url: 'pages/views/friends/AddFriend'})
    },
    {
      icon: $r('app.media.line_viewfinder'),
      value:'扫一扫',
      action: () => {}
    },
    {
      icon: $r('app.media.touched'),
      value:'收付款',
      action: () => {}
    }
  ])

整个项目所涉及知识点非常多,希望以上分享对大家有些帮助~


目录
打赏
0
1
2
0
136
分享
相关文章
鸿蒙NEXT时代你所不知道的全平台跨端框架:CMP、Kuikly、Lynx、uni-app x等
本篇基于当前各大活跃的跨端框架的现状,对比当前它们的情况和未来的可能,帮助你在选择框架时更好理解它们的特点和差异。
61 0
HarmonyOS NEXT仓颉开发语言实战案例:外卖App
仓颉语言实战分享,教你如何用仓颉开发外卖App界面。内容包括页面布局、导航栏自定义、搜索框实现、列表模块构建等,附完整代码示例。轻松掌握Scroll、List等组件使用技巧,提升HarmonyOS应用开发能力。
HarmonyOS NEXT仓颉开发语言实战案例:健身App
本期分享一个健身App首页的布局实现,顶部采用Stack容器实现重叠背景与偏移效果,列表部分使用List结合Scroll实现可滚动内容。代码结构清晰,适合学习HarmonyOS布局技巧。
HarmonyOS NEXT仓颉开发语言实战案例:银行App
仓颉语言银行App项目分享,页面布局采用List容器,实现沉浸式体验与模块化设计。顶部资产模块结合Stack与Row布局,背景图与内容分离,代码清晰易懂;功能按钮部分通过负边距实现上移效果,圆角仅保留顶部;热门推荐使用header组件,结构更规范。整体代码风格与ArkTS相似,但细节更灵活,适合金融类应用开发。
App Trace功能实战:一键拉起、快速安装与免提写邀请码的应用实践
App Trace系统通过一键拉起、快速安装和免提写邀请码三大功能,显著提升用户转化率、安装成功率和邀请注册率。结合深度技术实现与优化,助力公司用户增长,成为移动端核心基础设施。
基于uni-app+vite5+vue3实战短视频+直播+聊天app应用
基于uniapp+vue3+vite5从0-1实战搭建仿抖音/微信直播带货商城。集短视频+聊天+直播功能于一体。实现全屏沉浸式切换短视频/直播,支持编译运行到h5+小程序端+app端。
106 4
【HarmonyOS next】ArkUI-X新闻热搜聚合App【进阶】
本项目基于ArkUI-X框架,将鸿蒙(HarmonyOS)下的新闻热搜聚合App无缝迁移至iOS平台。采用ArkUI开发,结合@kit.NetworkKit实现网络请求,利用@ObservedV2与@Trace装饰器进行数据绑定,适配iOS界面布局与权限配置,完成跨平台热榜应用构建。
46 0
70. [HarmonyOS NEXT 实战案例九] 旅游景点网格布局(下)
在上一篇教程中,我们学习了如何使用GridRow和GridCol组件实现基本的旅游景点网格布局。本篇教程将在此基础上,深入探讨如何优化布局、添加交互功能,以及实现更多高级特性,打造一个功能完善的旅游景点应用。
68 1
|
1月前
|
69.[HarmonyOS NEXT 实战案例九] 旅游景点网格布局(上)
本教程将详细讲解如何使用HarmonyOS NEXT中的GridRow和GridCol组件实现旅游景点网格布局。通过网格布局,我们可以以美观、规整的方式展示各种旅游景点信息,为用户提供良好的浏览体验。
60 1

云原生

+关注

推荐镜像

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问