查看原文
其他

鸿蒙系列教程#02 | 从计数器认识布局基础

鸿洋
2024-12-13

The following article is from 编程之王 Author 张风捷特烈

第一篇:

鸿蒙纪·系列教程#01 - 环境搭建与项目结构




《鸿蒙纪元》 是 张风捷特烈[1] 计划打造的一套 HarmonyOS 开发系列教程合集。致力于创作优质的鸿蒙原生学习资源,帮助开发者进入纯血鸿蒙的开发之中。本系列的所有代码将开源在 HarmonyUnit[2] 项目中:
github: https://github.com/toly1994328/HarmonyUnit
gitee: https://gitee.com/toly1994328/HarmonyUnit
本文是《鸿蒙纪·梦始卷》 的第二章,上一篇介绍了环境搭建和初始项目,本篇将真正进入代码编写中,通过一个简单的计数器小功能,初步体验鸿蒙开发中的布局表现,以及交互行为:
[1]. 了解基础布局特性
[2]. 了解简单的交互行为和改变数据状态

[3]. 简单了解组件的封装与拆分

1从计数器认识简单的布局特性

HarmonyOS 应用开发使用的是 ArkUI 视图框架进行开发的,它也是一个 声名式 的 UI 框架。使用 TypeScript 的变种 ArkTs 语言进行开发。如果你有 Flutter 、 React 或 Compose 的开发经验,那么对 ArkUI 将驾轻就熟。
计数器是我非常喜欢的一个小案例,点击按钮使界面上的数字增加。它虽然非常简单,但麻雀虽小五脏俱全。从中可以了解界面编程的基本布局特性,也可以了解事件的回调以及界面数据更新的方式:
1. 列布局 Column 的背景和宽高
首先通过一个小案例看一下基本的布局特性,比如排列、背景色、边距、尺寸等。
• ArkUI 中背景色是所有组件的通用属性,通过 backgroundColor 方法可以指定组件颜色。
• Column 组件可以容纳多个组件,在自身区域内排布。
@Component
struct Index {
  build() {
    Column() {
      Text('计数器')
        fontSize(28)
        .fontWeight(FontWeight.Bold)
        .backgroundColor('#440000ff')
    }
    .backgroundColor('#44ff0000')
  }
}


上面代码中,让 Column 容纳一个 Text 文本,可以看出 Column 的区域尺寸默认是其容纳组件的尺寸:


• ArkUI 中的尺寸也是所有组件的通用属性,通过 width 和 height 设置。
如下所示,将 Column 的 width 设置为 '100%',它将会横向铺满(红色示意)。并且其内容组件默认会 横向居中

当把 Column 的 height 设置为 '100%' 时,可以看到红色区域会占满全屏,这也表示 Column 自身的区域尺寸。

2. 对齐方式与边距
Column 组件有控制内容组件对齐方式的属性,比如这里想让文字水平方向居左,可以设置 alignItems(HorizontalAlign.Start) 。Column 具体的布局特性,将在以后详细展开。

现在想让文字离左边和上边有点边距,看上去不那么拥挤:

• ArkUI 中的边距也是所有组件的通用属性,通过 padding 和 margin 设置内边距和外边距。
padding 表示内边距,内边距属于组件的区域尺寸,如下所示,Text 的区域被扩张:

而外边距 margin 不会影响 Text 的实际区域尺寸,只是进行偏移:

如果去除 Text 颜色,两者在视觉表现上没有区别,但实际的布局效果是不同的。所以,在视图布局的学习过程中,设置背景色查看布局区域,可以很好地辅助理解布局特性。

3 计数器布局

Column 中可以容纳多个组件,如下所示,其中可以再放置一个粉色的 Column,此时高度 100% 会占据高度的剩余的部分。

在粉色的 Column 中,放置两个文字组件,如下所示:

现在希望让两行文字在 竖直方向 居中显示,可以设置 Column 的 justifyContent 为 FlexAlign.Center 。此时去掉测试区域的颜色,就可以得到期望的计数器布局效果:



4.学习小技巧

到这里标记一个小的里程碑,下面是 Index.ets 的所有代码。可以通过 git 提交一下,大家可以通过每次的提交,记录当前的完整项目;同时,通过里程碑,也可以回顾自己开发过程的点滴成长。我也会在每个小里程碑放上一个提交记录,大家可以直接访问链接查看代码: 计数器-布局-v1[3]
@Entry
@Component
struct Index {
  @State message: string = '鸿蒙纪元';

  build() {
    Column() {
      Text('计数器')
        .fontSize(28)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 20, left: 20 })
      Column() {
        Text('下面是你点击按钮的次数:')
          .fontSize(18)
        Text('0')
          .fontSize(36)
          .fontColor('#2e3032')
          .margin({ top: 10 })
      }
      .width('100%')
      .height('100%')
      .justifyContent(FlexAlign.Center)
    }
    .alignItems(HorizontalAlign.Start)
    .width('100%')
    .height('100%')
  }
}

由于布局组件的属性和方法比较多,大家在学习过程中可以有意的记录一下遇到的知识点,有利于梳理、积累、沉淀:


2层叠布局与按钮、图标展示

这一小节我们将实现如下的布局界面,并实现按钮点击时增加计数器的数值:
打开时
点击按钮
1. 按钮和图标的展示
通过 Button 可以展示按钮,type 设置为 ButtonType.Circle 以圆形展示;stateEffect 为 true 时,点击可以有颜色加深的反馈效果。
图标通过
 SymbolGlyph 组件展示,可以加载系统内置的图标资源。所以得资源可以在官方的 harmonyos-symbol[4] 中查看。使用 fontSize 设置大小、fontColor 设置颜色、fontWeight 设置字重。
Button({ type: ButtonType.Circle, stateEffect: true }) {
  SymbolGlyph($r('sys.symbol.plus'))
    .fontSize(24)
    .fontColor([Color.White])
    .fontWeight(FontWeight.Bold)
}.width(56).height(56)

2. Stack 层叠布局
层叠布局可以让对个组件自下而上层层排列,通过 alignContent 可以设置子组件的对齐方式,比如这里设置为右下方 BottomEnd,按钮也就对齐到右下。可以通过对按钮设置外边距空出右侧和下方的间隔,从而完成想要的布局效果:
3. 简单的状态变化
我们称界面上随交互变化的数据为 可变状态量,比如当前需求下,可变状态量是呈现的数值,会随着按钮点击交互而增加。组件内部可以通过 @State 声明可变状态量,即如下的 counter 变量。按钮可以通过 onClick 设置点击的回调事件监听,只需要触发 counter 增加,界面上的数值就会自动更新渲染:
struct Index {
  @State counter: number = 0;

  Button(//略同...
    .onClick(()=>this.counter++ )
这里按钮触发的逻辑只有一行,这样写起来比较简单。如果是比较复杂的逻辑,建议提取一个函数(方法) 进行处理,更利于分离视图构建逻辑和行为数据逻辑 的代码,比如提取 increment 方法处理数据增加的业务逻辑; 按钮点击时触发 this.increment 即可。这样如果行为需求有什么变更,直接在 increment 方法中处理即可,方便定位代码和拓展功能:
increment(): void {
  this.counter++;
}

  Button(//略同...
    .onClick(()=>this.increment() )
大家可以继续梳理一下已经遇到的知识点,计数器的基本功能完成了,可以再提交一个小里程碑 计数器-v2-基本功能[5]


3组件封装

目前项目中,所有的代码都放在一块,点击这里查看 Index.ets[6]。嵌套结构看起来可读性很差。随着后面功能需求的增加,代码量会激增。学会合理地拆分组件,进行独立维护,是个很好的习惯。
比如头部标题栏是一个相对独立的区域,以后可能有被修改 和复用的可能,就可以将它视为一个组件来单独维护。使用 @Component 声明一个组件,在其中的 build 方法中处理构建逻辑:
1. 拆分 AppBar
应用的头部栏可以被其他界面复用,也会遇到修改的需求。适合拆分出来单独处理,比如下面使用 @Component 声明一个 AppBar 组件,构造是可以传入 title 字符串指定展示的标题文字。这里通过 Row 组件可以让若干个子组件横向排列,通过 justifyContent(FlexAlign.Center) 可以让子组件居中对其:

@Component
struct AppBar {
  private title: string = '';

  build() {
    Row() {
      Text(this.title)
        .fontSize(20).fontWeight(FontWeight.Bold)
        .fontColor($r('sys.color.white'))
    }
    .backgroundColor('#317bd4')
    .width('100%')
    .height(56)
    .padding({ left: 20, right: 20 })
    .justifyContent(FlexAlign.Center)
  }
}
如果其他界面中也需要构建类似的头部栏,每次都写一遍的话很不优雅。布局结构是类似的,无非是一些配置属性的差异,可以通过构造传参来指定数据。如下所示,AppToolBar 可以通过 title 指定文字标题:
如果你有其他的自定义属性,可以自行添加,比如背景色、高度等。
对于组件构建来说,设置插槽可以增加布局的灵活性。比如 AppBar 的首尾部分,使用者想要自己传入组件,来满足更多样化的使用场景:
那左侧的 leading 来说,通过 @BuilderParam 声明是组件构建者参数;通过 leadingBuilder 设置默认的构建器。构建器需要通过 @Builder 注解标识:
@Component
struct AppBar {
  private title: string = '';

  @Builder
  leadingBuilder() {}

  @Builder
  tailingBuilder() {}

  @BuilderParam leading: () => void = this.leadingBuilder;
  @BuilderParam tailing: () => void = this.tailingBuilder;

  build() {
    Row() {
      this.leading()
      Text(this.title)
        .fontSize(20).fontWeight(FontWeight.Bold)
        .fontColor($r('sys.color.white'))
      this.tailing()
    }
    .backgroundColor('#317bd4')
    .width('100%')
    .height(56)
    .padding({ left: 20, right: 20 })
    .justifyContent(FlexAlign.SpaceBetween)
  }
}
这样在 AppBar 构造时,可以通过 leading 参数,让外界构建具体内容,插入到 AppBar 结构的内部。通过这种方式,我们就可以封装一些通用的结构,便于复用:

到此,我们遇到的几个注解也可以整理一些,进入知识树中。知识树在一开始并不需要尽善尽美,它是你点滴的积累。可以在后续不断随着知识累计,调节各个枝点。这里再提交一个小里程碑 计数器-v3-组件简单封装[7]


4尾声


到这里,我们就已经完成了一个简单的计数器功能,并简单地认识鸿蒙开发中界面的布局已经组件封装。下一章我们将继续完善当前的计数器,了解沉浸标题栏、资源文件的使用、国际化的处理、布局调试工具的使用,敬请期待 ~

    引用链接

    [1] 张风捷特烈: 

    https://juejin.cn/user/149189281194766
    [2] HarmonyUnit:
    [3] 计数器-布局-v1: 

    https://github.com/toly1994328/HarmonyUnit/tree/8c15c41e5577312c33440e5fdbbcceda173b80e5
    [4] harmonyos-symbol: 

    https://developer.huawei.com/consumer/cn/design/harmonyos-symbol

    [5] 计数器-v2-基本功能: 

    https://github.com/toly1994328/HarmonyUnit/tree/994916b2e1866bb1898dfb9fe348b231261c8767

    [6] 点击这里查看 Index.ets: 

    https://github.com/toly1994328/HarmonyUnit/blob/994916b2e1866bb1898dfb9fe348b231261c8767/entry/src/main/ets/pages/Index.ets
    [7] 计数器-v3-组件简单封装:

     https://github.com/toly1994328/HarmonyUnit/tree/994916b2e1866bb1898dfb9fe348b231261c8767
    [8] 张风捷特烈: 

    https://juejin.cn/user/149189281194766
    [9] 张风捷特烈: 

    https://space.bilibili.com/390457600




    最后推荐一下我做的网站,玩Android: wanandroid.com ,包含详尽的知识体系、好用的工具,还有本公众号文章合集,欢迎体验和收藏!


    推荐阅读

    Android H5页面性能分析策略
    AndroidManifest中uses-library怎么起作用的?
    Android | 扩大View点击区域的几种方式



    扫一扫 关注我的公众号

    如果你想要跟大家分享你的文章,欢迎投稿~


    ┏(^0^)┛明天见!

    继续滑动看下一个
    鸿洋
    向上滑动看下一个

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存