前段时间 Harmony Next 不再兼容 Android 的音讯满天飞,各个大厂也开端对纯血 HarmonyOS 进行适配了,一般开发者也能够下载 DevEco Studio 进行尝鲜,相信大部分同学现已尝过鲜了,甚至有一部分现已着手开端了适配计划了。
现在 HarmonyOS 4.0 的一些 API 还不太老练,第三方SDK也在开发中,想复刻老练的原生运用或许为时尚早,不过咱们用 ArkTS 来画页面和完成一些简单的业务逻辑还绰绰有余的 。
最近公司也开端了复刻 HarmonyOS 版别的尝鲜计划,Android iOS 客户端开发全员上阵。咱们的 iOS 小伙伴说,除了 SwiftUI,鸿蒙这套 ArkTS 画页面也太快了吧,底子停不下来;不过对于Android 开发来说,特别是之前写过RN、Flutter 或者Compose的来说,写起来无外乎换一套API,成本相对是比较小的。
不过我想吐槽一下 Harmony 的开发文档写的是真不怎么样
开端
话不多说,直接开端。相信大家对 ArkTS 现已有一定了解,画布局现已不在话下。例如,用 RelativeContainer 画个 Hello World:
RelativeContainer() {
Text('Hello World')
.id("text")
.alignRules({
center: { anchor: "__container__", align: VerticalAlign.Center },
middle: { anchor: "__container__", align: HorizontalAlign.Center },
})
}
.width('100%')
.height('100%')
查看 RelativeContainer 的写法和文档,发现它就是 Android RelativeLayout 的 ArkTS 版别,与 RelativeLayout 的功用相同,一起又有一些不同:
- 增强了居中对齐功用,支撑根据某个控件的某个方向的中心进行对齐
- 不支撑基线对齐 (
baseline
) - 所有子组件有必要强制声明 id,不支撑 id 有效性的检查(重复或者不存在的情况),Parent id 的关键字是
__container__
- 所有对齐的锚点
anchor
不支撑代码补全,只能靠手敲 - 对齐规矩写法繁琐
- 不支撑相互束缚(Parent <– A <—> B –> Parent)
属实是一点优点没学到,iOS同学写Xib的看了都直摇头。
那有没有计划来优化 RelativeContainer 对齐规矩写法呢,经过对TS语法一顿研究,发现能够经过工具方法来优化 alignRules 的写法:
优化 AlignRuleOption 特点结构体声明
alignRules(AlignRuleOption) 的入参 AlignRuleOption
有如下特点:
特点名 | 功用 | 对应 Android RelativeLayout 特点(根据Parent对齐的特点没有写) |
---|---|---|
left | 当时控件左面根据anchor的(左面、右边和水平方向中心)对齐 |
layout_alignLeft or layout_toRightOf
|
top | 当时控件上方根据anchor的(上方、下方和垂直方向中心)对齐 |
layout_alignTop or layout_below
|
right | 当时控件右边根据anchor的(左面、右边和水平方向中心)对齐 |
layout_alignRight or layout_toLeftOf
|
bottom | 当时控件下方根据anchor的(上方、下方和垂直方向中心)对齐 |
layout_alignBottom or layout_above
|
center | 当时控件垂直方向中心根据anchor的(上方、下方和垂直方向中心)对齐 |
layout_centerVertical ,只支撑根据父容器居中对齐 |
middle | 当时控件水平方向中心根据anchor的(左面、右边和水平方向中心)对齐 |
layout_centerHorizontal ,只支撑根据父容器居中对齐 |
它们每个特点都是 { anchor: "id", align: (VerticalAlign|HorizontalAlign).* }
的结构体,能够对这些结构体声明进行优化:
// 把 `__container__` 提取成常量
export const Parent = "__container__"
// 声明垂直方向对齐特点成果类型
declare interface VerticalRule {
anchor: string,
align: VerticalAlign
}
// 声明水平方向对齐特点成果类型
declare interface HorizontalRule {
anchor: string,
align: HorizontalAlign
}
// 这两个接口首要是为了显示声明结构体特点类型
// API 9是能够不声明的
// API 10增强了代码检查需求声明返回值类型方法才或许return数据
export function toLeftOf(id: string): HorizontalRule {
return { anchor: id, align: HorizontalAlign.Start }
}
export function toRightOf(id: string): HorizontalRule {
return { anchor: id, align: HorizontalAlign.End }
}
export function centerHorizontalOf(id: string): HorizontalRule {
return { anchor: id, align: HorizontalAlign.Center }
}
export function toTopOf(id: string): VerticalRule {
return { anchor: id, align: VerticalAlign.Top }
}
export function toBottomOf(id: string): VerticalRule {
return { anchor: id, align: VerticalAlign.Bottom }
}
export function centerVerticalOf(id: string): VerticalRule {
return { anchor: id, align: VerticalAlign.Center }
}
修改上面Demo的代码
// 别忘了导包
import { centerHorizontalOf, centerVerticalOf, Parent, toBottomOf } from '../utils/RelativeContainerExtend';
RelativeContainer() {
Text('Hello World')
.id("text")
.alignRules({
center: centerVerticalOf(Parent),
middle: centerHorizontalOf(Parent),
})
.backgroundColor(Color.Red)
Text("Test")
.id("test")
.alignRules({
left: centerHorizontalOf("text"),
top: toBottomOf("text")
})
.backgroundColor(Color.Green)
}
.width('100%')
.height('100%')
是不是认为到这里就结束了,No No No,咱们还能够再进一步
优化 AlignRuleOption 整体声明
咱们能够让它更有 Android 特征,一起让API更明晰。
经过上面的 和 RelativeLayout xml 特点进行比照表格,发现它不太合适 RelativeLayout xml 特点的那套命名,反而更像 ConstraintLayout 的方位束缚特点,索性直接套 ConstraintLayout xml 的特点:leftToLeftOf,leftToRightOf 等等这些来扩展。首要声明支撑的特点:
declare interface AlignRules {
leftToLeftOf?: string,
leftToRightOf?: string,
rightToLeftOf?: string,
rightToRightOf?: string,
topToTopOf?: string,
topToBottomOf?: string,
bottomToTopOf?: string,
bottomToBottomOf?: string,
// 居中特点
centerOf?: string,
centerHorizontalOf?: string,
centerVerticalOf?: string,
}
然后增加一个方法将 AlignRules 转换为 AlignRuleOption,一起对一些居中情况进行特别处理
/**
* 构建相对布局规矩
* @param rules
* @returns
*/
export function buildRules(rules: AlignRules): AlignRuleOption {
let _left: HorizontalRule | undefined = undefined
if (rules.leftToLeftOf != null && rules.leftToRightOf != null) {
throw Error("leftToLeftOf 和 leftToRightOf 不能一起束缚")
} else if (rules.leftToLeftOf != null) {
_left = toLeftOf(rules.leftToLeftOf!)
} else {
_left = toRightOf(rules.leftToRightOf!)
}
let _right: HorizontalRule | undefined = undefined
if (rules.rightToLeftOf != null && rules.rightToRightOf != null) {
throw Error("rightToLeftOf 和 rightToRightOf 不能一起束缚")
} else if (rules.rightToLeftOf != null) {
_right = toLeftOf(rules.rightToLeftOf!)
} else {
_right = toRightOf(rules.rightToRightOf!)
}
let _middle: HorizontalRule | undefined = undefined
if (
rules.centerHorizontalOf != null ||
(_left != null && _right != null &&
_left.anchor == _right.anchor &&
_left.align == HorizontalAlign.Start &&
_right.align == HorizontalAlign.End)
) {
_middle = rules.centerHorizontalOf != null ? centerHorizontalOf(rules.centerHorizontalOf!) : centerHorizontalOf(_left.anchor!)
_left = undefined
_right = undefined
}
let _top: VerticalRule | undefined = undefined
if (rules.topToTopOf != null && rules.topToBottomOf != null) {
throw Error("topToTopOf 和 topToBottomOf 不能一起束缚")
} else if (rules.topToTopOf != null) {
_top = toTopOf(rules.topToTopOf!)
} else {
_top = toBottomOf(rules.topToBottomOf!)
}
let _bottom: VerticalRule | undefined = undefined
if (rules.bottomToTopOf != null && rules.bottomToBottomOf != null) {
throw Error("bottomToTopOf 和 bottomToBottomOf 不能一起束缚")
} else if (rules.bottomToTopOf != null) {
_bottom = toTopOf(rules.bottomToTopOf!)
} else {
_bottom = toBottomOf(rules.bottomToBottomOf!)
}
let _center: VerticalRule | undefined = undefined
if (
rules.centerVerticalOf != null ||
(_top != null && _bottom != null &&
_top.anchor == _bottom.anchor &&
_top.align == VerticalAlign.Top &&
_bottom.align == VerticalAlign.Bottom)
) {
_center = rules.centerVerticalOf != null ? centerVerticalOf(rules.centerVerticalOf!) : centerVerticalOf(_top.anchor!)
_top = undefined
_bottom = undefined
}
if (rules.centerOf != null) {
_middle = centerHorizontalOf(rules.centerOf)
_center = centerVerticalOf(rules.centerOf)
_left = undefined
_right = undefined
_top = undefined
_bottom = undefined
}
return {
left: _left,
right: _right,
middle: _middle,
top: _top,
bottom: _bottom,
center: _center,
}
}
再看看上面的Demo代码怎么写:
import { buildRules, Parent } from '../utils/RelativeContainerExtend';
@Extend(Text)
function styling() {
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor(Color.Black)
}
@Entry
@Component
struct Index {
build() {
Navigation() {
RelativeContainer() {
Text('Hello World')
.margin(12)
.styling()
.id("text")
.alignRules(buildRules({
centerOf: Parent
}))
.backgroundColor(Color.Red)
Text("Left")
.id("left")
.styling()
.alignRules(buildRules({
rightToLeftOf: "text",
centerVerticalOf: "text"
}))
.backgroundColor(Color.Brown)
Text("Right")
.styling()
.id("right")
.alignRules(buildRules({
leftToRightOf: "text",
centerVerticalOf: "text"
}))
.backgroundColor(Color.Green)
Text("Top")
.styling()
.id("top")
.alignRules(buildRules({
bottomToTopOf: "text",
centerHorizontalOf: "text"
}))
.backgroundColor(Color.Yellow)
Text("Bottom")
.styling()
.id("bottom")
.alignRules(buildRules({
topToBottomOf: "text",
centerHorizontalOf: "text"
}))
.backgroundColor(Color.Orange)
}
.width('100%')
.height('100%')
}
.width('100%')
.height('100%')
.title("Hello HarmonyOS")
.titleMode(NavigationTitleMode.Mini)
}
}
总结
到此对 RelativeContainer 的扩展也就结束了,期盼已久的完好代码立刻就来
直接将RelativeContainerExtend.ets
复制到项目中即可运用