从零开始开发纯血鸿蒙应用之实现起始页

news2025/1/7 10:20:12

从零开始开发纯血鸿蒙应用

  • 一、前言
  • 二、主要页面
  • 三、应用起始页
  • 四、MainPageContent 实现
    • 1、一级结构
    • 2、二级结构
      • 2.1、EmptyContent
      • 2.2、FileListContent
        • 2.2.1、ViewAction:
        • 2.2.2、EditAction
        • 2.2.3、DeleteAction
        • 2.2.4、ShareAction
  • 五、载入起始页的时机
  • 五、总结

一、前言

从本篇开始,将对 TxtEdit 的业务功能进行逐一实现,而业务功能是宿主在一个个具体的应用页面上的,所以,当务之急,便是将 TxtEdit 的主要页面、即用于编辑和浏览纯文本文件的页面进行实现。

目前,第一版实现中,主要页面有如下几个:
在这里插入图片描述
像那些用于说明app开发者信息,以及进行问题反馈等页面,个人认为属于非关键的主要页面,因此,在应用开发过程中,其优先级较低,可以放在最后去实现。

二、主要页面

TxtEdit 在版本 1.0.x 的主要页面,共有三套:

  • 应用起始页,由一个 page 文件组成
  • 内部文件处理页,由两个 page 文件组成,分别用于编辑和浏览应用的沙箱文件
  • 外部文件处理页,也是两个 page 文件组成,用于浏览和导入。

三、应用起始页

应用起始页,由 Index.ets 文件实现,页面路由为 pages/Index,它的代码内容结构如下:
在这里插入图片描述
根据 build 函数体,可知 TxtEdit 的起始页,和众多app的起始页一样,都是采用 Tabs 组件进行页面结构搭建,我这里,由于追求简洁和实用,Tabs 里面的 TabContent 也即所谓 Tab 页,只有两个。

在鸿蒙UI中,Tabs 组件具有横向纵向两种方向,并且 tabBar 也即 Tab 页标题栏,允许传入一个注解 @Builder 的 UI 构建函数,从而实现更美观或更个性化的应用起始页,由于本人美术天赋较差,设计不出让人眼前一亮的 UI 样式,只有如下的简简单单的:

@Builder
tabBuilder(title: string, targetIndex: number) {
  Column() {
    Text(title)
      .fontColor(this.currentIndex === targetIndex ? '#ff0af10a' : '#fff5f6f5')
  }
  .width('100%')
  .height(60)
  .justifyContent(FlexAlign.Center)
}

只做了根据Tab页是否被选中进行Tab标题颜色的变更。

为了达到 Tabs 组件居底布局,页面标题居顶布局,我将 Tabs 套在一个使用了 BottomColumn 样式的 Column 文件中,再将这个 Column 放在一个使用 RootTopColumn 样式的 Column 文件中。

TxtEdit 的起始页中的第一个 Tab 页,即文件 Tab 页,顾名思义,用于展示文件列表,方便用户进行内部文件的操作和管理,这时候,涉及到无内部文件和有内部文件两种状态的页面内容,要以什么样的方式进行载入?

方案不外乎两种,一种是在 TabContent 里面直接做条件渲染,根据条件使用不同的Content ,另一种是TabContent 里面使用一个直接展示的 Content,将条件渲染下移到该Content里面

本人采取的就是第二种方案:

build() {
  Column(){
    PageTitleBar({ title: 'TxtEdit'})
    Column(){
      Tabs(){
        TabContent(){
          Column(){
            MainPageContent()
          }.attributeModifier(this.centerColumn)
        }.tabBar(this.tabBuilder('文件', 0))
        TabContent(){
          AboutPageContent()
        }.tabBar(this.tabBuilder('关于', 1))
      }.attributeModifier(this.blackTabs)
      .onChange((index) => {
        this.currentIndex = index
      })
    }.attributeModifier(this.bottomColumn)
  }.attributeModifier(this.rootContainer)
}

四、MainPageContent 实现

在我尚未叙述具体实现时,屏幕前的你,对于 MainPageContent 的实现,心里有什么样的方案?是否认为,用一个类似 if-else 的语法结构,就能够实现无文件页面和有文件页面的载入显示?

如果是这样,那么你大概没有考虑到,用户场景存在着一种情况,就是从有文件到无文件的状态回退。此外,实时的 UI 刷新,比如用户创建第一个文件结束后,回到起始页,应当将用户创建的文件展示在文件列表中,而不是要用户杀掉app进程重新进入才能看到。

总的来说,app页面的实现,并非是想当然而,需要将可能的动态刷新场景兜底住,才能给用户一个较好的UI体验和交互操作体验。

1、一级结构

本篇后续,以及后面的每一篇博文,为了控制篇幅,主要是内容字符数,源码会贴的比较少,更多以图片的形式展示,完整源码还请访问gitee仓库获取,当然了,gitCode仓库也是准备了的。

在这里插入图片描述
由简入繁,先看一下函数体都收起时的内容。整体上,在 MainPageContent 中,最开始的地方,定义了一组辅助 UI 刷新的私有字段或状态变量,其中,状态变量是触发 UI 刷新所不可或缺的。

在页面即将渲染时,也即生命周期函数 aboutToAppear 所对应的阶段,需要做一些初始化工作:
在这里插入图片描述
利用项目内部 API,即 FileUtil 去获取内部文件的文件名列表,并且根据列表的空与非空,决定最终渲染的内容是 EmptyContent 还是 FileListContent,我这里所采用的条件渲染控制,并非鸿蒙UI所支持的 if-else 语法,而是组件属性 visibility,如此做法,其考量就是让UI代码更纯粹些
在这里插入图片描述
为了满足实时刷新UI内容的需要,doRefresh 函数做了如下工作:
在这里插入图片描述
虽然,和 aboutToAppear 很像,却也是必不可少的,毕竟已经通过装饰器 @Watch 与 refresh 做了绑定,而 refresh 实际上是一个应用全局的UI状态存储 中的字段,利用应用全局的UI状态存储机制,可以做到在B页面控制A页面进行UI更新,具体用法后面会给出。

2、二级结构

MainPageContent 的二级结构,实际对应的就是 EmptyContent 和 FileListContent。鉴于 EmptyContent 的实现更为简单,所以分析顺序就从 EmptyContent 开始。
在这里插入图片描述

2.1、EmptyContent

在这里插入图片描述

如图所示,开始处也是一批字段的定义,其中的 dialog 字段实际是一个 自定义弹窗
在这里插入图片描述
通过代入 CustomDialogController 的参数 alignment,将弹窗设置为页面居中显示,这里需要提醒一下 DevEco Studio 的 UI 预览器和真机显示上,在自定义弹窗上的区别,预览器显示弹窗是默认居中的,但真机则不是如此;另一个带入 CustomDialogController 的参数,用于控制是否允许自动关闭弹窗,即点击弹窗外的区域时是否允许关闭弹窗,显然,我这里设置为不允许,因此,弹窗的关闭只能通过显示在弹窗上的两个按钮去进行:
在这里插入图片描述
这个弹窗的打开动作,我将它放在“新建或导入按钮”中。

2.2、FileListContent

在这里插入图片描述
FileListContent 的结构,与 EmptyContent 的结构很相似,只不过“新建或导入”按钮上方,变成了一个列表组件。列表组件的列表项,根据fileList也即内部文件名列表动态生成,每个列表项都是由 RecentFileItem 实现:
在这里插入图片描述
RecentFileItem 的实现如下:
在这里插入图片描述
其显示效果如图:
在这里插入图片描述
点击“操作”文本,会有弹出式菜单显示出来,该菜单提供四个操作:查看、编辑、分享和删除。弹出式菜单的使用,只需在鸿蒙UI组件的bindMenu传入菜单绘制方法即可,也就是这里的 OptionMenu 方法:
在这里插入图片描述
四个操作的响应逻辑,通过 RecentFileItem 的四个函数参数载入,每一个具体实现逻辑,下面一一介绍:

2.2.1、ViewAction:

在这里插入图片描述
该动作的含义,就是浏览当前列表项对应的沙箱文件,实现代码比较简单,就是将对应的沙箱文件名通过路由参数带入到 ViewFilePage 中。

2.2.2、EditAction

在这里插入图片描述
动作含义就是编辑当前列表项对应的沙箱文件,由于实现代码与 ViewAction 类似,便不过多赘述。

2.2.3、DeleteAction

在这里插入图片描述
动作含义就是删除当前列表项对应的沙箱文件,在实现方面,主要用项目内部 API FileUtil.deleteFile(this.ctx, item) 实现文件的删除,而在删除成功的回调处理中,会对 TxtEdit 的起始页进行 UI 更新,即当最后一个内部文件被删除时,起始页重新显示无文件对应的页面内容;否则仍旧显示文件列表

2.2.4、ShareAction

在这里插入图片描述
该动作的含义,就是分享当前列表项对应的沙箱文件,在具体实现方面,也是用了一个项目内部 API,其都对应的具体代码如下:
在这里插入图片描述
主要就是利用鸿蒙系统提供的系统分享面板进行文件的分享:
在这里插入图片描述
要呼出如上的系统分享面板,需要做以下几方面的工作:
1)判断要分享的文件是否存在,避免引起其他应用出现异常
2)获取待分享文件对应的 utdTypeId
3)借助 systemShare.SharedData 包装分享内容,因为系统分享面板只接受 systemShare.SharedData 的数据
4)创建并持有 systemShare.ShareController,即系统分享面板控制器
5)借助系统分享面板控制器拉起系统分享面板,并对是否成功拉起面板进行回调处理

五、载入起始页的时机

在鸿蒙应用开发框架中,应用起始页的载入时机为,应用声明周期函数 onWindowStageCreate
在这里插入图片描述
在该函数中,会通过系统 API windowStage.loadContent 去加载某个 Page 作为起始页,而这里就是 'pages/Index'

五、总结

正所谓台上一分钟台下十年功,看起来很简单的应用起始页,实现起来往往需要对多种动态刷新和操作交互进行处理,更需要保证页面间的数据流透传方向不出错、以及应用全局范围的信号起作用等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2271577.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux(Ubuntu24.04)源码编译安装VTK7.1.1记录

VTK(Visualization Toolkit)是一个开源的3D可视化开发工具包,用于开发可视化和图形处理应用程序。VTK提供了一系列的算法和工具,用于创建、渲染和处理复杂的3D图形和数据。VTK由C编写,并提供了Python、Java和Tcl等语言…

三、GIT与Github推送(上传)和克隆(下载)

GIT与Github推送(上传)和克隆(下载) 一、配置好SSH二、在Github创建仓库三、git克隆(下载)文件四、git推送(上传)文件到远程仓库 一、配置好SSH Git与Github上传和下载时需要使用到…

SpringCloudAlibaba实战入门之Sentinel服务降级和服务熔断(十五)

一、Sentinel概述 1、Sentinel是什么 随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。 一句话概括:sentinel即Hystrix的替代品,官网: https://sentinelguard.io/zh…

24年无人机行业资讯 | 12.23-12.29

24年无人机行业资讯 | 12.23-12.29 1、 国家发改委新设低空经济司,助力低空经济规范发展2、商务部支持无人机民用国际贸易,强调出口管制与安全并重3、滨州高新区首架无人机成功下线4、 2025第九届世界无人机大会筹备推进会顺利召开5、2024年世界无人机竞…

前端实现大文件上传(文件分片、文件hash、并发上传、断点续传、进度监控和错误处理,含nodejs)

大文件分片上传是前端一种常见的技术,用于提高大文件上传的效率和可靠性。主要原理和步骤如下 文件分片 确定分片大小:确定合适的分片大小。通常分片大小在 1MB 到 5MB 之间使用 Blob.slice 方法:将文件分割成多个分片。每个分片可以使用 Bl…

源代码编译安装X11及相关库、vim,配置vim(1)

一、目录结构 如下。 所有X11及相关库装到mybuild,源代码下载到src下,解压,进入,编译安装。编译时指定--prefix到相同的目录,即上图中mybuild。 ./configure --prefixpwd/../../mybuild [CFLAGS"-I/path/to/X11…

bytetrack 解决跟踪后框晃动的问题

使用距离最近的匹配的检测框 替代 bytetrack返回的跟踪框 作为最终的返回结果 完整byte_tracker.py代码为: import numpy as np from collections import deque import os import os.path as osp import copy import torch import torch.nn.functional as Ffrom …

如何使用OBS Studio录制屏幕?

可以进入官网或github进行下载: https://obsproject.com/download 安装包解压后进入bin 进入64-bit 选择obs 64 进入OBS Studio后在来源内右键,选择添加 选择添加显示器采集即可录取整个屏幕,窗口采集可选择窗口进行录制 选择对应显示器即配置…

ArcGIS Server 10.2授权文件过期处理

新的一年,arcgis server授权过期了,服务发不不了。查看ecp授权文件,原来的授权日期就到2024.12.31日。好吧,这里直接给出处理方法。 ArcGIS 10.2安装时,有的破解文件中会有含一个这样的注册程序,没有的话&…

循环冗余校验CRC的介绍

一、简介 循环冗余校验CRC(Cyclic Redundancy Check)是数据通信领域中最常用的一种差错校验码。该校验方法中,使用多项式出发(模2除法)运算后的余数为校验字段。CRC只能实现检错,不能实现纠错,使…

消息中间件类型都有哪些

在消息中间件的专业术语中,我们可以根据其特性和使用场景将其划分为几种主要的类型。这些类型不仅反映了它们各自的技术特点,还决定了它们在不同应用场景下的适用性。 1. 点对点(Point-to-Point)消息中间件: • 这类中…

微信小程序中 “页面” 和 “非页面” 的区别

微信小程序中 “页面” 和 “非页面” 的区别,并用表格进行对比。 核心概念: 页面 (Page): 页面是微信小程序中用户可以直接交互的视图层,也是小程序的基本组成部分。每个页面都有自己的 WXML 结构、WXSS 样式和 JavaScript 逻辑…

卸载wps后word图标没有变成白纸恢复

这几天下载了个wps教育版,后头用完了删了 用习惯的2019图标 给兄弟我干没了??? 其他老哥说什么卸载关联重新下 ,而且还要什么撤销保存原来的备份什么,兄弟也是不得不怂了 后头就发现了这个半宝藏博主&…

SQL Server导出和导入可选的数据库表和数据,以sql脚本形式

一、导出 1. 打开SQL Server Management Studio,在需要导出表的数据库上单击右键 → 任务 → 生成脚本 2. 在生成脚本的窗口中单击进入下一步 3. 如果只需要导出部分表,则选择第二项**“选择具体的数据库对象(Select specific database objects)”**&am…

基于SpringBoot在线竞拍平台系统功能实现十五

一、前言介绍: 1.1 项目摘要 随着网络技术的飞速发展和电子商务的普及,竞拍系统作为一种新型的在线交易方式,已经逐渐深入到人们的日常生活中。传统的拍卖活动需要耗费大量的人力、物力和时间,从组织拍卖、宣传、报名、竞拍到成…

Android Camera压力测试工具

背景描述: 随着系统的复杂化和业务的积累,日常的功能性测试已不足以满足我们对Android Camera相机系统的测试需求。为了确保Android Camera系统在高负载和多任务情况下的稳定性和性能优化,需要对Android Camera应用进行全面的压测。 对于压…

配置嵌入式服务器

一、如何定制和修改Servlet容器的相关配置 修改和server有关的配置(ServerProperties) server.port8081 server.context‐path/tx server.tomcat.uri-encodingUTF-8二、注册servlet三个组件【Servlet、Filter、Listener】 由于SpringBoot默认是以jar包…

GPIO、RCC库函数

void GPIO_DeInit(GPIO_TypeDef* GPIOx); void GPIO_AFIODeInit(void); void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct); void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct); //输出 读 uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx,…

3D高斯点云CUDA版本数据制作与demo运行

0. 简介 关于UCloud(优刻得)旗下的compshare算力共享平台 UCloud(优刻得)是中国知名的中立云计算服务商,科创板上市,中国云计算第一股。 Compshare GPU算力平台隶属于UCloud,专注于提供高性价4090算力资源,配备独立IP,…

框架模块说明 #09 日志模块_01

背景 日志模块是系统的重要组成部分,主要负责记录系统运行状态和定位错误问题的功能。通常,日志分为系统日志、操作日志和安全日志三类。虽然分布式数据平台是当前微服务架构中的重要部分,但本文的重点并不在此,而是聚焦于自定义…