当前位置: 首页 > article >正文

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

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

  • 一、前言
  • 二、主要页面
  • 三、应用起始页
  • 四、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.kler.cn/a/467946.html

相关文章:

  • 安卓14无法安装应用解决历程
  • 66.基于SpringBoot + Vue实现的前后端分离-律师事务所案件管理系统(项目 + 论文)
  • qml PathView详解
  • VisionPro软件Image Stitch拼接算法
  • hot100_54. 螺旋矩阵
  • 浅谈棋牌游戏开发流程七:反外挂与安全体系——守护游戏公平与玩家体验
  • 【方案设计】针对监控服务-功能时长统计的几个实现方案
  • 云备份项目--服务端编写
  • Oracle 11g rac + Dataguard 环境调整 redo log 大小
  • React虚拟DOM:理解和应用
  • torch.reciprocal介绍
  • 游戏引擎学习第70天
  • 面试题解,Java中的“对象”剖析
  • 【js引擎】quickjs 中的两个 proto
  • 5 Linux 网络编程基础 API
  • 家教老师预约平台小程序系统开发方案
  • 数据结构-顺序表及其应用
  • 【pytorch练习】使用pytorch神经网络架构拟合余弦曲线
  • 电商项目-基于ElasticSearch实现商品搜索功能(一)
  • 2025-01-04 Unity插件 YodaSheet1 —— 插件介绍
  • 【深度学习入门_基础篇】线性代数本质
  • 进军AI大模型-Langchain程序部署
  • DS复习提纲模版
  • asp.net core 发布到iis后,一直500.19,IIS设置没问题,安装了sdk,文件夹权限都有,还是报错
  • RestClient操作Elasticsearch
  • 【Java】集合中的List【主线学习笔记】