5
头图

HarmonyOS 5.0(NEXT)实战体验—"慢小圈"应用开发实战体验全流程

在智能化、全场景的数字时代,HarmonyOS作为华为自主研发的操作系统,正逐渐改变着我们的生活方式与工作环境。随着HarmonyOS 5.0(NEXT)的发布,鸿蒙生态迎来了更多创新与突破,尤其是在元服务的开发与应用上。元服务作为鸿蒙生态的核心组成部分,凭借其跨设备、跨平台的特点,为用户提供了更加智能化、个性化的服务体验。

本篇文章将深入探讨HarmonyOS 5.0(NEXT)版本中,如何进行“慢小圈”元服务的开发与应用。从基础的开发环境搭建到元服务的实际构建,我们将全面介绍整个开发流程,帮助开发者更好地理解鸿蒙生态下的服务创新与技术实现。无论是鸿蒙开发的新手,还是已有一定经验的开发者,都能通过本文的实战体验,快速掌握开发技巧,并为未来的数字化转型打下坚实的基础。

"慢小圈"应用的部分截图如下:

image-20241124191431842

一、共码未来,待到山花烂漫时

在2024年10月22日的原生鸿蒙之夜暨华为全场景新品发布会上,华为常务董事、终端BG董事长、智能汽车解决方案BU董事长余承东公布了鸿蒙生态的最新进展。HarmonyOS的代码行数已超过1.1亿行,成为数字底座中最具生命力的系统之一。在中国市场,鸿蒙的市场份额位居第二,品牌认知度和开发者数量也实现了显著增长。目前,已有超过15,000个鸿蒙原生应用和元服务上架,且部分原生应用的迭代速度接近每天一个版本。同时,鸿蒙生态设备数量突破10亿台,标志着历史性突破的到来。这些成就充分体现了鸿蒙生态的强大潜力和发展动力。

z.png

二、什么是HarmonyOS 5.0(NEXT)?

HarmonyOS 5.0,也称为HarmonyOS NEXT或“纯血鸿蒙”,是华为公司自主研发的全新一代操作系统。

  • 2024年10月22日,华为在深圳举办“原生鸿蒙之夜暨华为全场景新品发布会”,正式发布了HarmonyOS 5.0。
  • HarmonyOS 5.0的发布标志着华为在操作系统领域的又一重大突破,它与苹果iOS系统和谷歌安卓系统共同构成了全球移动操作系统的三大鼎足之势。

2.1 设计理念

HarmonyOS 5.0(NEXT)以“和谐美学”为核心理念,重新定义了用户界面的美学和交互体验。它运用“光构建出世界的万物”的哲学进行界面设计,将光的元素引入到操作系统的设计中,利用算法模拟按钮的光照效果,提升了界面的视觉冲击力和动态交互感。

2.2 核心特点

HarmonyOS 5.0(NEXT)在多个方面实现了显著提升。首先,流畅度相比前一版本提高了30%,续航也增加了56分钟,得益于系统架构和性能优化的持续努力。该系统还支持跨设备协同,能够实现智能手机、智能家居设备、汽车信息娱乐系统等多设备间的无缝连接与数据共享,极大提升了用户体验。、

此外,HarmonyOS 5.0(NEXT)搭载了全新的小艺助手,基于盘古大模型打造的系统级AI,为用户提供更加智能的应用场景和服务,如快速生成论文摘要、思维导图等。安全方面,系统采用了全新的安全架构,降低了隐私泄露的风险,同时支持文件加密分享和分布式安全架构,确保用户数据安全。

HarmonyOS 5.0(NEXT)还注重个性化与定制化,提供了丰富的主题、动态壁纸和重力感应动效,让用户能够根据个人需求进行定制设置,享受更加个性化的视觉与操作体验。

image-20241124155506905

2.3 应用场景

HarmonyOS 5.0(NEXT)的应用场景非常广泛,不仅适用于智能手机和平板电脑等移动设备,还适用于智能家居、汽车信息娱乐系统等。它能够实现设备之间的无缝连接和协同工作,让用户在不同场景下都能享受到便捷和智能的体验。

智能家居场景

在智能家居场景中,HarmonyOS 5.0(NEXT)可以实现智能家居设备的无缝连接和智能控制。用户可以通过智能手机或平板电脑上的HarmonyOS应用,轻松管理家中的智能灯泡、智能插座、智能空调、智能门锁等设备。例如,当用户离家还有一段距离时,可以通过手机提前开启家中的空调,调节到舒适的温度;或者当用户忘记锁门时,可以通过手机远程锁定智能门锁,确保家庭安全。此外,HarmonyOS 5.0(NEXT)还支持智能家居设备的场景联动,如设置“回家模式”自动开启灯光和空调,设置“离家模式”自动关闭家中所有电源等,让家居生活更加智能化和便捷化。

汽车信息娱乐系统场景

在汽车信息娱乐系统场景中,HarmonyOS 5.0(NEXT)可以实现智能手机与汽车信息娱乐系统的无缝连接和协同工作。用户可以通过手机将导航信息、音乐列表等同步到汽车信息娱乐系统上,实现无缝切换和共享。例如,当用户驾车前往某个目的地时,可以将手机上的导航信息直接投射到汽车信息娱乐系统的屏幕上,方便用户查看路线和导航信息;或者当用户想要听某首音乐时,可以通过手机将音乐列表发送到汽车信息娱乐系统上,享受高品质的音乐播放体验。此外,HarmonyOS 5.0(NEXT)还支持语音助手功能,用户可以通过语音指令控制汽车信息娱乐系统的各项功能,提高驾驶安全性和便利性。

image-20241124160246055

办公场景

在办公场景中,HarmonyOS 5.0(NEXT)可以实现多设备之间的协同办公,提高工作效率。用户可以通过智能手机、平板电脑和电脑等设备之间的无缝连接和协同工作,实现文件共享、会议协同等功能。例如,当用户需要在不同设备之间传输文件时,可以通过HarmonyOS的分布式文件系统实现文件的快速共享和同步;或者当用户需要参加视频会议时,可以通过HarmonyOS的视频通话功能实现多设备之间的视频协同和屏幕共享,提高会议效率和沟通效果。

image-20241124160221425

教育场景

在教育场景中,HarmonyOS 5.0(NEXT)可以为学习者提供更加智能化和个性化的学习体验。通过智能手机、平板电脑等设备,学习者可以轻松获取各种学习资源,如在线课程、电子书、习题等。同时,HarmonyOS 5.0(NEXT)还支持智能推荐功能,根据学习者的学习情况和兴趣爱好推荐相关的学习资源和学习路径。此外,学习者还可以通过HarmonyOS的协同功能与其他学习者或教师进行交流和互动,共同解决问题和提高学习效果。

三、鸿蒙应用创建过程全流程

在本章中,我们将详细介绍如何从零开始创建一个鸿蒙应用,涵盖从环境搭建、项目创建到最终应用运行的整个过程。通过本章的学习,将掌握鸿蒙应用开发的基础步骤,并能够自主进行应用的开发与调试。

在开始开发鸿蒙应用之前,首先需要确保开发环境的配置完成。以下是必要的环境准备工作:

  • 安装 DevEco Studio:DevEco Studio是华为官方推荐的开发工具,支持鸿蒙应用的开发与调试。请确保从官网或其他正规渠道下载并安装最新版本的DevEco Studio。
  • 华为开发者账号:创建鸿蒙应用并发布到华为应用市场,需要有一个华为开发者账号。如果尚未注册,可以访问华为开发者官网完成注册。
  • 配置开发设备或模拟器:确保设备或模拟器可以用于调试和运行鸿蒙应用。可以使用真实设备,也可以使用DevEco Studio自带的模拟器。

3.1 项目目标

本项目旨在帮助开发者掌握从环境搭建到应用发布的完整鸿蒙应用开发流程。通过学习项目创建、功能开发、调试测试、打包发布等步骤,开发者将能够独立完成鸿蒙应用的开发、调试与上线,并具备持续维护与更新的能力。通过本项目的实践,开发者将深入理解鸿蒙系统的架构和开发工具,为构建高质量的鸿蒙应用打下坚实的基础。

image-20241127172800322

3.2 项目创建

image-20241127172815545

image-20241127172155822

首先,打开 DevEco Studio,点击 New -> Create Project,然后在模板选择页面中选择 Application。首次创建项目时,系统会提示你登录华为账号。此时,请点击 登录,并注意,这里需要登录的是开发者账号,即用于应用上架的账号。如果你是企业用户,建议使用公司的开发者账号进行登录。

image-20241127172848177

完成模板选择后,进行项目配置,并创建项目。待工程代码自动生成完成后,项目创建过程将如图所示。

image-20241124163148079

image-20241127172626746

在完成项目创建并成功配置后,我们就可以进入开发阶段,开始愉快地进行元服务的开发工作了。这一步标志着项目的正式启动,接下来可以利用HarmonyOS的强大功能,进行元服务的设计与实现,探索更多创新的应用场景,为用户提供更加流畅和智能的体验。

3.3拓展阅读:理解鸿蒙万能卡片的概念

虽然本项目不是元服务,但作为HarmonyOS 应用开发的特色之一,我们必须有所了解。鸿蒙万能卡片是一种将元服务的关键重要信息以卡片的形式展示出来的界面组件。它秉承了HarmonyOS系统一次开发多端部署、可分可合自由流转、统一生态原生智能的三大应用与服务开发理念,支持运行在多种HarmonyOS终端设备上。

比如在之前开发的元服务中,我们可以直接使用使用卡片来展示地貌风景。

image.png

对于开发者而言,鸿蒙万能卡片的开发相对简单且高效。HarmonyOS系统提供了丰富的组件、接口与流量入口,开发者只需开发与上架一次,便可以部署在各种HarmonyOS终端设备上。同时,基于常驻桌面的卡片入口和更丰富的场景推荐,开发者能够获得更多的自然流量,从而降低后期运营成本。

用户在使用鸿蒙万能卡片时,可以通过滑动、点击等操作与卡片进行交互。卡片可以根据用户的操作进行展开、收缩或跳转至相关服务。此外,用户还可以自定义卡片的大小、位置以及显示内容,以满足个性化的需求。

四、Harmony Next 实战—“慢小圈”鸿蒙应用

在本章中,我们将通过实际案例开发一个基于HarmonyOS Next的应用——“慢小圈”应用,帮助大家深入理解如何利用鸿蒙系统的最新技术和功能来创建一个高效、智能的跨设备应用。通过本章的学习,您将掌握鸿蒙应用开发的关键流程和技术要点。

编辑器版本:DevEco Studio 5.0.1 Beta3 面向HarmonyOS应用及元服务开发者提供的集成开发环境(IDE),助力高效开发。

API版本:13

4.1 项目背景

“慢小圈”是一款旨在帮助用户提高生活效率、进行信息管理和任务协作的应用。通过创新的功能设计和鸿蒙系统的跨设备能力,它可以在智能手机、平板、智能家居等设备之间实现无缝协同。利用HarmonyOS 5.0(NEXT)的优势,我们可以为用户提供流畅、高效的多设备互动体验。

4.2 应用架构

“慢小圈”应用的架构基于鸿蒙系统的多层次分布式能力。它通过多个模块和Ability的协作,确保用户可以在不同设备间流畅地同步任务、管理数据和执行操作。该应用由以下几个核心部分组成:

  • 主界面Ability:展示用户的任务和日程信息,并提供便捷的操作入口。
  • 任务管理Ability:负责创建、编辑和同步任务,确保任务在不同设备间实时更新。
  • 智能助手模块:集成了鸿蒙的智能助手,通过语音和智能推荐系统,帮助用户自动化管理任务和提醒。

4.3 创建应用项目

  1. 初始化项目:在DevEco Studio中选择 New -> Create Project,选择 Empty Ability 模板进行项目初始化。根据项目需求设置应用的基本信息和模块结构,创建一个基础的鸿蒙应用框架。
  2. 配置项目环境:在项目的配置文件中,设置所需的权限和API,以便实现任务同步、跨设备协作等功能。

image-20241124162714501

4.4 功能开发

在“慢小圈”鸿蒙应用的开发过程中,功能开发是关键环节之一。本节将详细介绍几个主要页面的开发流程,包括登录页面、个人中心页面、个人计划TODO表页面和“慢小圈”页面。每个页面都将展示如何使用HarmonyOS的技术来实现流畅的用户体验,并集成鸿蒙的核心功能。

4.4.1 登录页面开发

登录页面是应用的第一步入口,用户通过该页面进行身份验证并进入应用。

image-20241124165048689

上图是“慢小圈”的登录页面,其实现代码如下:

@Entry
@Component
struct Page {
  @State message: string = 'Hello World'
  build() {
    Column() {
      Column() {
        Row() {
          Image($r("app.media.logo"))
            .width("100vp")
            .height("100vp")
        }
        .width("100%")
        .height("100vp")
        .position({ x: "0", y: "95vp" })
        .justifyContent(FlexAlign.Center)
        Text("慢小圈")
          .width("100%")
          .height("50vp")
          .position({ x: "0", y: "200vp" })
          .textAlign(TextAlign.Center)
          .fontSize("26fp")
        Text("登录账号以使用更多服务")
          .width("100%")
          .height("30vp")
          .position({ x: "0", y: "250vp" })
          .fontColor("#808080")
          .textAlign(TextAlign.Center)
          .fontSize("14fp")
        Text("忘记密码")
          .width("150vp")
          .height("40vp")
          .offset({ x: "105vp", y: "99.68vp" })
          .fontSize("14fp")
        Text("短信验证码登录")
          .width("150vp")
          .height("40vp")
          .offset({ x: "-87.68vp", y: "59.2vp" })
          .fontSize("14fp")
        Text("注册账号")
          .width("150vp")
          .height("40vp")
          .offset({ x: "0vp", y: "214.86vp" })
          .textAlign(TextAlign.Center)
          .fontSize("14fp")
        TextInput({ placeholder: "密码" })
          .width("100%")
          .height("50vp")
          .position({ x: "0vp", y: "350.52vp" })
          .type(InputType.Password)
        TextInput({ placeholder: "用户名" })
          .width("100%")
          .height("50vp")
          .position({ x: "0vp", y: "288.5vp" })
        Button("登录")
          .width("90%")
          .height("40vp")
          .offset({ x: "0vp", y: "129.43vp" })
          .fontSize("20fp")
        Grid() {
          GridItem() {
          }
          .width("33.3%")
          .height("100%")
          .offset({ x: "0vp", y: "0vp" })
        }
        .width("98%")
        .height("76.01vp")
        .position({ x: "4.2vp", y: "90%" })
      }
      .width("100%")
      .height("100%")
      .justifyContent(FlexAlign.Center)
    }
    .width("100%")
    .height("100%")
  }
}

下面是对代码每个部分的解析

  1. @Entry@Component 注解
  • @Entry@Component 是装饰器(decorators),这表明 Page 组件是应用的入口(@Entry)并且是一个UI组件(@Component)。这在某些UI框架中常见,例如React、Flutter等。
  1. struct Page@State
  • struct Page 定义了一个页面组件,类似于React中的class或者function
  • @State 注解标识了 message 变量作为组件的状态,并初始化为 'Hello World'
  1. build() 方法
  • build() 是一个函数,负责构建页面的布局。返回的内容描述了整个页面的结构。

页面布局的层次结构

页面使用的是类似于 Flexbox 布局的方式,包含了多层 ColumnRow 组件,它们将其他组件组织成垂直或水平排列。具体结构如下:

第一层 Column

  • 最外层的 Column() 组件占据整个页面 (width: "100%"height: "100%")。
  • 它包含一个子 Column(),这个子列也占据页面的全部空间。

第二层 Column 组件

  • 这里是实际构建页面的部分,包含了多个子组件:

    1. RowImage

      • 一个 Row(),用于水平排列内容。
      • 其中包含了一个 Image 组件,用于显示应用的 logo,$r("app.media.logo") 表示获取资源。
      • 图片设置了 100vp 的宽度和高度,并被放置在页面的 95vp 处,靠近底部。
    2. Text 组件:

      • "慢小圈" 文本显示在页面中心,字体大小 26fp,占据100%宽度并且居中。
      • "登录账号以使用更多服务" 是页面中的提示文本,字体大小 14fp,颜色为灰色(#808080),也居中显示。
      • "忘记密码""短信验证码登录""注册账号" 是页面中的链接或按钮文本,设置了不同的坐标偏移和字体大小。
    3. TextInput 组件:

      • "密码""用户名" 输入框被设置了占满100%宽度,并分别定位在特定的 y 坐标上。
      • "密码" 输入框的类型被设置为 InputType.Password,这意味着它是密码输入框。
    4. Button 组件:

      • "登录" 按钮被设置为 90% 宽度,字体大小 20fp,也有一定的偏移量(y: "129.43vp")。

其他布局组件

  • GridGridItem

    • 使用了 Grid() 来分配空间。它包含一个 GridItem,宽度是 33.3%,高度为100%。
    • Grid 的大小占用了页面的 98% 宽度和约 76% 的高度。

布局细节

  • 页面使用了 positionwidthheightoffsetjustifyContenttextAlign 等布局属性来控制各个组件的显示位置和样式。
  • 使用 FlexAlign.CenterTextAlign.Center 来确保内容居中对齐。

这段代码通过声明式的方式构建了一个登录页面的UI,包含了应用logo、文本信息、输入框和按钮等基本UI组件,布局上使用了 ColumnRow 组件来实现垂直和水平排列。每个组件都被精细定位和调整以实现所需的界面效果。

本节介绍了“慢小圈”登录页面的开发,利用声明式语法构建了一套简洁而高效的布局,包括应用 logo、提示文本、输入框及功能按钮等基本组件。通过使用 ColumnRow 实现灵活的垂直与水平排列,结合 vpfp 单位保障了响应式适配,并采用 @State 管理组件状态,为后续功能扩展奠定了基础。这种模块化和精细化设计确保了页面的美观性与可维护性。

4.4.2 个人中心页面开发

个人中心页面是用户管理个人信息和应用设置的核心页面。

image-20241124173100234

上图是“慢小圈”的个人中心页面,其实现代码如下:

interface MenuToType{
  title:string;
  url:Resource;
}
@Entry
@Component
export struct TabUser {
  @State nickname: string = '慢小圈';
  @State signature: string = '00001';

  @State menuTopList:MenuToType[] = [
    {
      title:"我的动态",
      url:$r("app.media.t1")
    },
    {
      title:"我的主页",
      url:$r('app.media.t2')
    },
    {
      title:"我的粉丝",
      url:$r('app.media.t3')
    },
    {
      title:"我的段位",
      url:$r('app.media.t4')
    }
  ];
  @State MenuList: MenuToType[] = [
    {
      title: "我的任务",
      url: $r('app.media.tasks') // 任务页面的链接
    },
    {
      title: "任务统计",
      url: $r('app.media.statistics') // 任务统计页面
    },
    {
      title: "团队协作",
      url: $r('app.media.team') // 团队协作页面
    },
    {
      title: "个人资料",
      url: $r('app.media.profile') // 个人资料页面
    },
    {
      title: "设置",
      url: $r('app.media.settings') // 设置页面
    },
    {
      title: "帮助与反馈",
      url: $r('app.media.help') // 帮助与反馈页面
    }
  ];

  build() {
    Column() {
      // 顶部
      Column(){
        Flex({justifyContent:FlexAlign.Start,alignItems:ItemAlign.Center}){
          Image($r('app.media.jiji'))
            .width(50)
            .height(50)
            .borderRadius(60)
            .margin({right:10})
          Column(){
            Text(this.nickname)
              .fontSize(16)
              .width('100%')
              .textAlign(TextAlign.Start)
            Text('ID: '+this.signature)
              .fontSize(12)
              .margin({top:5})
              .textAlign(TextAlign.Start)
              .width('100%')
          }
        }
        .width('100%')
        Flex({justifyContent:FlexAlign.SpaceAround}){
          Column(){
            Text('10')
              .fontSize(16)
            Text('关注')
              .fontSize(14)
          }
          Column(){
            Text('100')
              .fontSize(16)
            Text('收藏')
              .fontSize(14)
          }
          Column(){
            Text('300')
              .fontSize(16)
            Text('访客')
              .fontSize(14)
          }
          Column(){
            Text('90')
              .fontSize(16)
            Text('点赞')
              .fontSize(14)
          }
        }.margin({top:30})

      }.width('100%')
      .padding(20)
      .height(200)
      .backgroundImage($r('app.media.bgg'))

      //主体内容
      Column(){
        Row(){
          ForEach(this.menuTopList, (item:MenuToType) => {
            Column()
            {
              Image(item.url)
                .width(40)
              Text(item.title)
                .width('100%')
                .fontSize(14)
                .margin({top:10})
                .textAlign(TextAlign.Center)
            }.width('25%')
          })
        }.width('100%')
        .backgroundColor('#ffffff')
        .borderRadius(15)
        .padding(15)

        Column(){
          ForEach(this.MenuList, (item:MenuToType) => {
            Row(){
              Row(){
                Image(item.url)
                  .width(20)
                  .margin({right:10})
                Text(item.title)
                  .fontSize(14)
              }
              Image($r('app.media.g1'))
                .width(15)

            }.width('100%')
            .justifyContent(FlexAlign.SpaceBetween)
            .borderWidth({bottom:1})
            .borderColor('#f7f7f7')
            .padding({top:12,bottom:12})
          })
        }
        .backgroundColor('#ffffff')
        .borderRadius(15)
        .padding(15)
        .width('100%')
        .margin({top:10})
      }
      .width('100%')
      .padding(15)
      .margin({top:-40})


    }
    .backgroundColor('#f7f7f7')
    .height('100%')
    .width('100%')
  }
}

下面是对代码每个部分的解析

这段代码定义了一个用户界面组件 TabUser,它主要用于展示用户的个人信息以及一些与用户相关的菜单项。该组件使用声明式语法来构建UI,并且借助了状态管理和布局系统来组织界面内容。以下是代码的详细解析:

  1. 组件装饰器和定义

TabUser 是一个组件,使用了 @Entry@Component 装饰器:

  • @Entry 表示该组件是一个入口点或主页面。
  • @Component 表示这是一个组件,可能是框架中的一个UI组件,负责渲染用户界面。
  1. 组件的状态管理 (@State)

组件内部使用了多个状态变量来存储用户的基本信息和菜单项:

  • nicknamesignature 分别存储了用户的昵称和个性签名。
  • menuTopListMenuList 分别存储了顶部和底部的菜单项。每个菜单项有一个标题和关联的资源URL。
  1. UI布局结构

组件的UI是通过 ColumnRowForEach 等布局组件嵌套来实现的。整体界面可以分为几个主要部分:

  • 顶部区域:显示用户的头像、昵称和签名。头像是一个圆形图像,昵称和签名显示在头像旁边。
  • 统计数据:显示用户的一些统计数据,如关注、收藏、访客、点赞等,每个统计项通过 Column 布局显示,并与相应的文本标签一起呈现。
  • 菜单区:分为两部分:

    • 顶部菜单menuTopList):使用 ForEach 遍历列表,动态渲染每个菜单项的图标和标题。
    • 底部菜单MenuList):显示任务、统计、团队协作等内容,同样使用 ForEach 遍历,展示每个菜单项的图标和标题,同时还有一个小图标表示操作按钮。
  1. 样式和布局
  • 使用了 Flex 布局来进行灵活的对齐(如 FlexAlign.StartItemAlign.Center)和空间分配(如 FlexAlign.SpaceAround)。
  • 使用了 margin, padding, width, height 等属性来控制布局间距和尺寸。
  • 各个区域之间使用了 backgroundImagebackgroundColor 来设置背景图和背景色。
  1. 动态数据渲染
  • ForEach 用于遍历 menuTopListMenuList,并根据每个列表项动态渲染UI元素(如菜单项的图标和标题)。这表示界面的内容可以根据数据的变化而自动更新。
  1. 整体布局结构

整体布局是嵌套的 ColumnRow 结构:

  • 外层 Column 包含了顶部区域和主体内容。
  • 顶部区域和菜单区域的布局是通过 ColumnRow 混合使用来实现的,确保内容的排列方式符合预期的视觉效果。

该组件构建了一个类似个人主页的UI,展示了用户的个人信息、统计数据和菜单项。布局结构采用了灵活的响应式设计,通过 ForEach 动态渲染菜单项,确保UI根据数据的变化能够自动更新。

本节介绍了“慢小圈”个人中心页面的开发,其设计结合了灵活的布局和状态管理,实现了用户信息展示和功能导航。页面包含头像、昵称、统计数据及菜单项等模块,利用 @State 动态绑定用户数据,通过 ForEach 遍历实现菜单内容的动态渲染。布局采用 ColumnRow 配合 Flex 实现灵活排列,样式设计上使用了圆形头像、背景图及圆角边框等元素,确保页面的视觉美观与可维护性,是个人中心页面的完整解决方案。

4.4.3 个人计划TODO表页面开发

TODO表页面是应用中的核心功能之一,允许用户管理和记录自己的任务和计划。

image-20241124190118484

上图是“慢小圈”的TODO页面,其实现代码如下:

@Component
export default struct Item {
  private content?: string;
  @State isComplete: boolean = false;

  @Builder
  labelIcon(icon: Resource) {
    Image(icon)
      .objectFit(ImageFit.Contain)
      .width(28)
      .height(28)
      .margin(20)
  }
  build() {
    Row() {
      if (this.isComplete) {
        this.labelIcon($r('app.media.no'));
      } else {
        this.labelIcon($r('app.media.yes'));
      }
      Text(this.content)
        .fontSize(20)
        .fontWeight(500)
        .opacity(this.isComplete ? 0.4 : 1.0)
        .decoration({ type: this.isComplete ? TextDecorationType.LineThrough : TextDecorationType.None })
    }
    .borderRadius(12)
    .backgroundColor("#FFFFFF")
    .width("100%")
    .height("64vp")
    .onClick(() => {
      this.isComplete = !this.isComplete;
    })
  }
}

这段代码是一个使用装饰器和组件化结构编写的UI组件,用于展示一条带图标和文字的项目项(Item),并支持切换完成状态。以下是代码的功能解析:

  1. 状态管理

    • isComplete: 表示项目是否已完成的状态,初始值为 false,由 @State 装饰器标注以支持组件状态管理。
    • 切换 isComplete 状态后,UI 会自动更新,显示不同的图标和文字样式。
  2. 动态渲染

    • 图标和文字样式会根据 isComplete 状态动态调整。
    • 如果 isCompletetrue,显示特定图标(no)和带删除线的文字。
    • 如果 isCompletefalse,显示另一个图标(yes)和正常的文字样式。
  3. 点击交互

    • 整个项目项是可点击的。点击后,通过 onClick 回调函数切换 isComplete 状态,并实时更新UI。

各部分功能详细解析

  1. 组件定义

    • 通过 @Component 声明一个名为 Item 的组件。
    • 组件包含一个可选的 content 属性用于显示文字内容。
  2. labelIcon 方法

    • 使用 @Builder 装饰器定义,负责创建一个图标的样式。
    • 参数是资源类型(Resource),通过方法链设置图标的大小、边距和适配方式。
  3. build 方法

    • 定义组件的整体布局,使用一个水平排布的

      Row

      容器来组织内容:

      • 图标:

        • 动态调用 labelIcon 方法,根据 isComplete 状态选择合适的图标资源(yesno)。
      • 文字:

        • 使用文字内容 content,动态设置其透明度、字体大小、加粗以及装饰效果(删除线或无装饰)。
    • 容器本身样式包括圆角、背景色、宽高等。
    • 添加了点击事件处理器(onClick),切换 isComplete 状态。

UI效果说明

  1. 初始状态

    • 显示图标(yes),文本为正常样式(无删除线、不透明)。
  2. 状态切换

    • 点击容器:

      • 图标切换为 no
      • 文本样式更新为带删除线且透明度降低。
    • 再次点击恢复原始状态。
  3. 交互性

    • 图标和文字样式的切换均为实时动态更新,表现出良好的交互效果。

适用场景

  • 适用于待办事项列表(To-Do List)或类似的任务管理场景。
  • 提供直观的状态反馈和便捷的状态切换功能。
import Item from './Item'
@Entry
@Component
struct Index {
  @State todo: string = '';
  @State list: Array<string> = [
    "学习鸿蒙开发",
    "阅读技术书籍",
    "参加线上会议",
    "练习编程",
    "听音乐放松",
    "锻炼身体",
    "开发个人项目",
  ];
  build() {
    Flex({ direction: FlexDirection.Column, }) {
      Text("待办事项")
        .width("100%")
        .fontSize(28)
        .fontWeight(FontWeight.Bold)
        .textAlign(TextAlign.Start)
        .margin({ bottom: 20 })
      TextInput({ text: this.todo, placeholder: "请输入" })
        .width("100%")
        .height(45)
        .enterKeyType(EnterKeyType.Done)
        .placeholderColor(Color.Gray)
        .margin({ bottom: 20 })
        .onChange((value) => {
          this.todo = value;
        })
        .onSubmit((value) => {
          console.log(String(value))
          this.list.push(this.todo)
          this.todo = ''
        })
      List({ space: 20 }) {
        ForEach(this.list, (item: string) => {
          ListItem() {
            Item({ content: item })
          }.width('100%')
        }, (item: string, i) => i + item)
      }
      .flexGrow(1)
      .edgeEffect(EdgeEffect.None)
    }
    .padding(18)
    .width('100%')
    .height('100%')
    .backgroundColor('#dddddd')
  }
}

这段代码定义了一个待办事项应用的主界面组件 Index,基于组件化结构,通过动态状态管理和输入输出的交互,实现了添加和展示待办事项的功能。以下是详细解析:

  1. 初始状态与数据

    • 使用两个

      @State

      变量管理数据:

      • todo:存储用户当前输入的待办事项。
      • list:初始化为一个包含多个待办事项的数组,用于存储所有事项。
  2. 用户交互

    • 用户可以通过输入框输入新任务,并通过提交事件(onSubmit)将其添加到列表中。
    • 新的待办事项会即时更新到UI,整个过程流畅自然。
  3. 布局与展示

    • 标题文本("待办事项")居上,设置了醒目的样式。
    • 输入框居中,用于添加新事项。
    • 待办事项列表展示在页面下方,使用自定义的 Item 组件渲染每一项。

关键部分解析

  1. 组件结构

    • 使用 @Entry 标记组件为应用的入口点。
    • 通过 @Component 声明 Index 为组件。
  2. 标题部分

    • 通过 Text 渲染标题,设置了加粗、较大字体的样式,并添加底部边距使布局更美观。
  3. 输入框功能

    • 通过

      TextInput

      组件实现用户输入功能:

      • text:绑定到 this.todo,实现双向数据绑定,实时更新输入内容。
      • placeholder:占位符提示用户输入。
      • onChange:监听用户输入的每一个变化,更新 todo
      • onSubmit:监听用户提交事件,将输入值添加到 list,并清空 todo
    • 提交后,新的待办事项会立即渲染到界面中。
  4. 待办事项列表

    • 使用

      List

      组件布局,并通过

      ForEach

      遍历

      list

      数组:

      • 每个待办事项渲染为一个 ListItem,并传递到自定义的 Item 组件中。
      • 为每一项绑定唯一的 keyi + item)以确保列表更新的高效性。
  5. 整体布局

    • 使用 Flex 容器设置为纵向布局(FlexDirection.Column),确保标题、输入框和列表按顺序堆叠。
    • 列表区域通过 flexGrow(1) 占据剩余空间,确保在内容较少时仍然填满页面。
    • 设置背景色为浅灰(#dddddd),增加视觉分层效果。

用户交互流程

  1. 初始显示

    • 显示标题、空输入框和初始化的待办事项列表。
  2. 添加新事项

    • 用户在输入框输入文字,点击键盘的提交键触发 onSubmit
    • 新事项被加入 list,同时清空输入框。
  3. 展示待办事项

    • 列表实时更新,展示所有事项。
    • 每一项通过 Item 渲染,包括状态切换功能(isComplete)。

UI效果

  1. 页面顶部显示标题。
  2. 居中显示输入框,带有占位提示。
  3. 下方为待办事项的垂直列表,每一项显示文字和状态切换按钮。
  4. 页面整体简洁,互动流畅。

适用场景

  • 个人任务管理(To-Do List)。
  • 简单的学习记录或任务跟踪应用。
  • 作为入门鸿蒙应用开发的示例项目。

潜在扩展方向

  1. 删除事项:为列表项添加删除按钮,实现事项的移除。
  2. 持久化存储:将 list 数据存储到本地或云端,实现数据的持久化。
  3. 多状态管理:支持事项优先级或分类管理功能,增强可用性。

在本节中,我们开发了一个简洁且功能齐全的TODO任务管理页面,利用鸿蒙框架的组件化特性,实现了待办事项的动态渲染、状态切换以及用户输入的交互处理。页面通过标题、输入框和任务列表的层次化布局,为用户提供了直观的任务添加和管理体验,同时支持实时状态更新和界面渲染。代码的高可扩展性还为后续功能的优化和完善奠定了基础,例如任务分类、优先级设置和数据持久化存储等。

4.4.4 圈子页面开发

“慢小圈”页面是应用的核心功能页面,专注于任务协作和信息共享。

image-20241124190804030

上图是“慢小圈”的圈子页面,其实现代码如下:

import navController from '@ohos.router';
class PostClass {
  public userAlias: string; // 用户昵称
  public postContent: string; // 贴文内容
  public imageGallery: ResourceStr[]; // 图片列表
  constructor(userAlias: string, postContent: string, imageGallery: ResourceStr[]) {
    this.userAlias = userAlias;
    this.postContent = postContent;
    this.imageGallery = imageGallery;
  }
}
@Entry
@Component
struct GalleryPage {
  @State postList: PostClass[] = [
    new PostClass('每日感悟', '教育的四大支柱,即学会求知,学会做事,学会共处,学会生存。', []),
    new PostClass('今日分享', '甫昔少年日,早充观国宾。读书破万卷,下笔如有神。', [$r("app.media.bg2")]),
    new PostClass('生活真相', '长风破浪会有时,直挂云帆济沧海。', [$r("app.media.bg3"), $r("app.media.bg4")]),
    new PostClass('每日思考', '妈妈看着我们慢慢长大,奔向前程;我们却只能看着妈妈逐渐老去,走向暮年。相同的岁月,却有不同的滋味。孩子在最懵懂的岁月里得到最多的呵护,把陪伴视为理所当然,等到懂得珍惜时,总是懊悔错过了许多时光。', [$r("app.media.icon"), $r("app.media.icon"), $r("app.media.icon")]),
    new PostClass('人生哲理', '人生如逆旅,我亦是行人。在岁月的长河中,我们都是匆匆过客,经历着风雨,也沐浴着阳光。每一次挑战都是成长的契机,每一次挫败都是灵魂的磨砺。', [$r("app.media.icon"), $r("app.media.icon"), $r("app.media.icon"), $r("app.media.icon")]),
  ];
  // 计算行数
  computeRowsTemplate(index) {
    let result: string = '1fr';
    let length: number = this.postList[index].imageGallery.length || 0;
    if (length == 1) {
      result = '1fr';
    } else if (length >= 2 && length <= 6 && length != 3) {
      result = '1fr 1fr';
    } else {
      result = '1fr 1fr 1fr';
    }
    return result;
  }
  // 计算列数
  computeColumnsTemplate(index) {
    let result: string = '1fr';
    let length: number = this.postList[ilery.length || 0;
    if (length == 1) {
      result = '1fr';
    } else if (length == 2 || length == 4) {
      result = '1fr 1fr';
    } else {
      result = '1fr 1fr 1fr';
    }
    return result;
  }
  // 计算高度
  computeGridHeight(index) {
    let result: number = 0;
    let length: number = this.postList[indeeGallery.length || 0;
    if (length <= 3) {
      result = 70;
    } else if (length > 3 && length <= 6) {
      result = 145;
    } else {
      result = 220;
    }
    return result;
  }
  // 计算宽度
  computeGridWidth(index) {
    let result: number = 0;
    let length: number = this.postList[indry.length || 0;
    if (length == 1) {
      result = 70;
    } else if (length == 2 || length == 4) {
      result = 145;
    } else {
      result = 220;
    }
    return result;
  }
  build() {
    Column() {
      List({ space: 20 }) {
        ListItem() {
          Stack({ alignContent}) {
            Column() {
              Image($r("app.media.back1"))
                .objesctFit(ImadgeFit.ver);
            }
            .width('100%')
            .height(300);
            Row({ space: 10 }) {
              Text('慢小圈')
                .fontSize(20)
                .fontColor(0xffffff)
                .margin({ bottom: 10 });
              Image($r("app.media.back2"))
                .width(80)
                .height(80)
                .borderRadius(8)
                .objesctFit(ImageFit.Cover);
            }
            .height(80)
            .justifyContent(FlexAlign.End)
            .padding(14);
          }
          .width('100%')
          .height(300);
        }
        ForEach(this.postList, (item: PostClass, index: number) => {
          ListItem() {
            Row({ space: 10 }) {
                .obsectFit(ImwgeFit.Cover);
              Column({ space: 10 }) {
                Text(`${item.userAlias}`)
                  .fontSize(16)
                  .fontColor('#409EFF');
                Text(item.postContent)
                  .fontSize(16)
                  .lineHeight(22);
                if (item.imageGallery && item.imageGallery.length > 0) {
                  Grid() {
                        Image(img)
                          .height(70)
                          .width(70)
                          .objectFit(ImageFit.Cover)
                          .borderRadius(2)
                      }
                    });
                  }
                  .columnsTemplate(this.computeColumnsTemplate(index))
                  .rowsTemplate(this.computeRowsTemplate(index))
                  .columnsGap(5)this.computeGridWidth(index))
                  .height(this.computeGridHeight(index));
                }
              }
              .layoutWeight(1)
              .alignItems(HorizontalAlign.Start)
              .justifyContent(FlexAlign.Start);
            }
            .width('100%')
            .alignItems(VerticalAlign.Top);
          }
          .width('100%')
          .paddin;
        });
      }
      .divider({ strokeWidth: 1 })
      .width('100%');
    }
    .width('100%')
    .height('100%');
  }
}

上述代码是一个用于鸿蒙OS开发的页面组件,展示了一个动态内容列表,其中每项可以包括用户昵称、贴文内容,以及图片列表。以下是代码解析:

核心结构

  1. PostClass类:

    • 定义了每个贴文的数据结构,包括:

      • userAlias: 用户昵称。
      • postContent: 贴文内容。
      • imageGallery: 贴文关联的图片列表。
  2. GalleryPage组件:

    • 组件使用了@State来管理动态数据postList,即多个PostClass对象。
    • build函数定义了组件的页面布局。

关键功能

  1. 动态图片布局:

    • computeRowsTemplate 
      computeColumnsTemplate
      • 根据图片数量动态计算网格的行列布局模板。
    • computeGridHeight
      computeGridWidth
      • 根据图片数量动态设置图片网格的宽高。
  2. 布局绘制:

    • 使用ColumnRow组件实现垂直与水平布局。
    • 每个列表项

      ListItem

      内容包括:

      • 用户头像与昵称。
      • 贴文内容。
      • 图片列表(用Grid布局)。
  3. 图片展示:

    • 当图片存在时,采用Grid组件动态生成网格布局,并通过ForEach逐一插入图片。

界面特点

  1. 顶部背景区域:

    • 使用Image组件设置顶部的背景图,以及右下角的头像与文字信息。
  2. 动态内容列表:

    • 通过ForEach迭代postList,为每个贴文生成独立的列表项。
  3. 图片网格:

    • 根据图片数量,自动调整行列数与布局,保证显示效果适配内容。

样式与优化

  • 自适应设计:

    • 动态宽高计算以及网格配置,保证不同图片数量下的显示效果一致。
  • 视觉层次感:

    • 使用边距与对齐方式,如justifyContentalignItems,保持内容排布整齐美观。
  • 代码扩展性:

    • 贴文与图片列表的数据结构清晰易扩展,可以轻松增加或修改字段。

适用场景

该组件适用于社交类应用的内容展示页面,如朋友圈、动态列表等,通过图片与文字的结合,提供良好的用户体验。

本节展示了“慢小圈”页面的开发,通过动态数据绑定和网格布局的自适应设计,呈现了一个内容丰富、结构灵活的任务协作与信息共享界面。代码实现涵盖了用户贴文数据的动态渲染、图片网格布局的自动适配,以及简洁美观的界面风格,为社交类应用提供了一个高效实用的实现方案。

4.5 效果截图

“慢小圈”核心页面截图如下:

image-20241124191431842

五、总结

本文详细介绍了在HarmonyOS 5.0(NEXT)版本下进行“慢小圈”元服务开发的全过程。从基础的开发环境搭建到元服务的实际构建,全面讲解了如何利用华为的鸿蒙生态进行高效的应用开发,帮助开发者理解和掌握鸿蒙平台的创新技术和开发流程。

HarmonyOS 5.0(NEXT)基于华为方舟引擎,通过软硬云生态的深度整合,HarmonyOS NEXT实现从系统到应用的全面流畅升级,整机流畅度提升30% ,续航增加约56分钟 ,运行内存平均节省1.5GB 。

image-20241124191902870

文章首先回顾了HarmonyOS 5.0的最新进展和核心特点,包括其跨设备协同、智能化服务和系统性能的显著提升。随后,深入探讨了HarmonyOS的设计理念、核心功能及其广泛的应用场景,涵盖了智能家居、汽车信息娱乐、办公与教育等多个领域,展示了HarmonyOS如何改变传统的数字体验。文章具体讲解了鸿蒙应用的开发流程,涵盖了从环境配置、项目创建到应用调试和发布的每一个环节,帮助开发者能够独立完成应用的开发与上线。同时,还介绍了鸿蒙系统中的“万能卡片”概念,它为开发者提供了一种便捷的方式来展示元服务的关键信息,并支持跨终端设备的部署和展示。

通过本文,开发者可以全面了解鸿蒙操作系统的最新功能和开发流程,为未来的数字化转型奠定技术基础。同时,鸿蒙生态的强大潜力和创新特性也为开发者提供了更多的应用开发机会,推动智能化和全场景的技术应用发展。

附录


阿波的朋友
3.5k 声望438 粉丝