4、UI构建基础:Column/Row布局、Text/Image/Button组件、Flex布局与主轴对齐方式
说实话,很多初学者一上来就盯着复杂的动画和自定义绘制,结果连最基本的页面布局都写得歪歪扭扭。我个人习惯是,先把这几个基础组件和布局吃透,后面写复杂页面才能游刃有余。今天咱们就聊聊 ArkTS 里最常用的那几样东西。
4.1 Column 和 Row:最朴素的“上下”与“左右”
Column 和 Row 是啥?说白了,Column 就是让子组件从上往下排,Row 就是从左往右排。你想想看,一个 App 页面,90% 的结构都能用这两个东西搭出来。
核心区别:
- Column:主轴是垂直方向(从上到下)
- Row:主轴是水平方向(从左到右)
我在项目中遇到过一个问题:有个新手同事把一堆按钮用 Column 包起来,结果按钮之间挤得死死的。嗯,这里要注意,Column 和 Row 默认是不给子组件加间距的,你得手动设置 space 参数。
// 正确的间距写法
Column({ space: 12 }) {
Text('第一行')
Text('第二行')
Text('第三行')
}
.width('100%')
.height(200)
.backgroundColor('#F5F5F5')
你看,加个 space: 12,子组件之间就有了 12vp 的间距。这个习惯我一直保持到现在,写布局第一件事就是先想好间距。
4.2 Text、Image、Button:三剑客
这三个组件,你写任何一个页面都绕不开。咱们一个一个说。
4.2.1 Text:不只是显示文字
Text 组件看起来简单,但坑不少。我曾经因为没设置 textAlign,导致文字在容器里偏左,怎么调都不对。后来才发现,Text 默认是左对齐的,你得显式指定。
Text('这是一段居中的文字')
.fontSize(16)
.fontColor('#333333')
.textAlign(TextAlign.Center) // 居中显示
.width('100%')
还有一点,Text 支持富文本样式,比如加粗、斜体、下划线。但我不建议你在一个 Text 里塞太多样式,拆成多个 Text 组件,代码可读性会好很多。
4.2.2 Image:图片加载的坑
Image 组件,说白了就是显示图片。但有个细节很多人忽略:图片的缩放模式。默认情况下,Image 会保持原图尺寸,如果你的容器比图片小,图片就会溢出。
避坑指南:我曾经在项目里直接用了 Image 没设置 objectFit,结果图片把整个页面撑变形了。后来我养成了习惯,只要用 Image,必写 objectFit(ImageFit.Cover) 或 ImageFit.Contain。
Image($r('app.media.example'))
.width(200)
.height(150)
.objectFit(ImageFit.Cover) // 裁剪填充,保证铺满容器
另外,网络图片记得加占位图或加载失败的回退图,不然用户看到一片空白,体验很差。
4.2.3 Button:交互的入口
Button 组件,ArkTS 里提供了好几种样式:ButtonType.Normal、ButtonType.Capsule、ButtonType.Circle。我个人习惯用 Capsule 风格,圆角看起来更现代。
Button('点击我')
.type(ButtonType.Capsule)
.backgroundColor('#007AFF')
.fontColor('#FFFFFF')
.fontSize(16)
.width(200)
.height(48)
.onClick(() => {
console.log('按钮被点击了')
})
嗯,这里要注意,Button 的点击事件里不要写太重的逻辑,比如网络请求。我一般只在 onClick 里调用一个函数,把具体逻辑抽出去,这样代码好维护。
4.3 Flex 布局:更灵活的排列方式
Column 和 Row 虽然好用,但遇到复杂的自适应布局就有点力不从心了。这时候 Flex 布局就派上用场了。Flex 可以同时控制主轴和交叉轴的对齐方式,说白了就是更灵活。
Flex 的核心参数:
direction:主轴方向(FlexDirection.Row 或 FlexDirection.Column)justifyContent:主轴对齐方式alignItems:交叉轴对齐方式
举个例子,你想让三个按钮在水平方向上均匀分布,用 Row 加 space 很难做到完美,但 Flex 一行代码就搞定:
Flex({
direction: FlexDirection.Row,
justifyContent: FlexAlign.SpaceEvenly,
alignItems: ItemAlign.Center
}) {
Button('按钮1')
Button('按钮2')
Button('按钮3')
}
.width('100%')
.height(60)
你看,SpaceEvenly 会让所有按钮之间的间距相等,包括两端的间距。这个在写底部导航栏或者工具栏时特别常用。
4.4 主轴对齐方式:细节决定成败
主轴对齐方式,说白了就是子组件在主轴方向上的排列规则。Flex 提供了几种对齐方式,我列个表,你一看就明白:
| 对齐方式 | 说明 | 适用场景 |
|---|---|---|
FlexAlign.Start |
从主轴起点开始排列 | 默认左对齐或上对齐 |
FlexAlign.Center |
居中对齐 | 标题居中、弹窗内容 |
FlexAlign.End |
从主轴终点开始排列 | 右下角悬浮按钮 |
FlexAlign.SpaceBetween |
两端对齐,中间间距相等 | 导航栏、列表项 |
FlexAlign.SpaceAround |
每个项目两侧间距相等 | 标签页、卡片布局 |
FlexAlign.SpaceEvenly |
所有间距(含两端)相等 | 均匀分布的按钮组 |
为什么会这样?其实这些对齐方式是从 CSS 的 Flexbox 借鉴过来的,如果你写过前端,应该很熟悉。但 ArkTS 里有个小区别:主轴方向变了,对齐方式的效果也跟着变。比如 FlexDirection.Column 时,Start 就是顶部对齐,End 就是底部对齐。
小技巧:我写布局时,习惯先用 Center 对齐把内容居中,然后再微调。这样能快速看到整体效果,避免一开始就纠结边边角角。
4.5 实战:一个简单的登录卡片
说了这么多,咱们来写个实际例子。一个登录卡片,包含图标、输入框和按钮,用 Column、Row 和 Flex 组合实现:
Column({ space: 20 }) {
// 顶部图标
Image($r('app.media.logo'))
.width(80)
.height(80)
.objectFit(ImageFit.Contain)
// 输入框区域
Column({ space: 12 }) {
TextInput({ placeholder: '请输入用户名' })
.width('100%')
.height(44)
TextInput({ placeholder: '请输入密码' })
.width('100%')
.height(44)
.type(InputType.Password)
}
.width('100%')
// 登录按钮
Button('登录')
.type(ButtonType.Capsule)
.backgroundColor('#007AFF')
.fontColor('#FFFFFF')
.width('100%')
.height(48)
.onClick(() => {
// 登录逻辑
})
// 底部链接
Flex({
direction: FlexDirection.Row,
justifyContent: FlexAlign.SpaceBetween
}) {
Text('忘记密码')
.fontColor('#666666')
.fontSize(14)
Text('注册账号')
.fontColor('#007AFF')
.fontSize(14)
}
.width('100%')
}
.width('90%')
.padding(20)
.backgroundColor('#FFFFFF')
.borderRadius(12)
.shadow({ radius: 8, color: '#1A000000' })
你看,这个登录卡片用 Column 做垂直布局,内部嵌套了 Row 和 Flex 做水平排列。整个结构清晰,而且每个组件都设置了合适的间距和对齐方式。我在实际项目中,这种卡片结构几乎每天都在用。
好了,这一章的内容就这些。Column/Row 是骨架,Text/Image/Button 是血肉,Flex 是关节。把这几个东西玩熟了,你写 UI 的效率至少提升一倍。下一章咱们聊聊更高级的布局技巧,比如相对布局和绝对定位,到时候见。