《解决界面交互痛点:WaterFlow 瀑布流、双层嵌套滚动、键盘避让与跨 Ability 跳转实践》
1. WaterFlow瀑布流
瀑布流布局的特点:
每一列盒子的宽度一致, 盒子的高度不一致
自上而下, 形成参差错落效果
waterFlow和Grid布局类似,都支持columnsTemplate和rowsTemplate通过 fr 的形式对行和列进行分割
常用参数{ }
- footer 设置WaterFlow尾部组件。(抽取@Builder)
- scroller 可滚动组件的控制器,与可滚动组件绑定
不允许和其他滚动类组件,如:List、Grid、Scroll等绑定同一个滚动控制对象。
常用属性
- .columnsTemplate('1fr 1fr') 设置列
- .rowsTemplate('1fr 1fr') 设置行
- .columnsGap(10) 列间隙
- .rowsGap(10) 行间隙
- .edgeEffect 边缘滚动效果 edgeEffect(EdgeEffect. ) Spring 弹簧效果
- .scrollBar 设置滚动条状态 默认值:BarState.Off
@Entry
@Component
struct WaterFlowCase {build() {// 顶级容器WaterFlow() {// 子组件 -> 有且只能有一个根组件FlowItem() {// 内容}}.columnsTemplate("1fr 1fr 1fr").columnsGap(20).rowsGap(20).padding(20)}
}
import { promptAction } from '@kit.ArkUI'@Entry
@Component
struct WaterFlowPage {build() {Column() {// 瀑布流基本使用// footer 到底了 显示的内容WaterFlow({ footer: this.footerBuilder() }) {ForEach(Array.from({ length: 10 }), () => {FlowItem() {Column() {Text('瀑布流').fontSize(30)}}.width('100%').height(50 * Math.floor(Math.random() * 10)).backgroundColor(Color.Pink)})}.columnsTemplate('1fr 1fr') //分割的数量.columnsGap(10) //间隔距离.rowsGap(10) //间隔距离// 触底时 触发事件 可在此发送请求加载数据.onReachEnd(() => {promptAction.openToast({message: '努力加载中...',})})}.height('100%').width('100%')}@BuilderfooterBuilder() {Text('到底了~')}
}
2. 双层嵌套滚动
父容器滚动 - 例如 : Scroll
子容器滚动 - 例如 : List
.nestedScroll({
scrollForward: NestedScrollMode.PARENT_FIRST, //上滑动 父组件优先
scrollBackward: NestedScrollMode.SELF_FIRST // 向下滑动 自己优先
})

// 父组件
@Entry
@Component
struct QianTaoHuaDong {build() {Column() {Scroll() {Column({ space: 10 }) {Swiper() {Text('1').styleTEXT(Color.Pink)Text('2').styleTEXT(Color.Blue)Text('3').styleTEXT(Color.Red)}Column() {itemList()}}}}.height('100%').width('100%')}
}@Extend(Text)
function styleTEXT(color: Color) {.width('100%').height(120).padding({ left: 10, right: 10 }).backgroundColor(color)
}
// 子组件
@Component
struct itemList {build() {List() {ForEach(Array.from({ length: 10 }), () => {ListItem() {Text('12345')}.width('100%').height(100).backgroundColor(Color.Orange)})}.divider({ strokeWidth: 10 }).scrollBar(BarState.Off).layoutWeight(1)// 不是list特有的属性,滚动组件都可设置,嵌套组件中 把他设置给 子组件.nestedScroll({scrollForward: NestedScrollMode.PARENT_FIRST, //上滑动 父组件优先scrollBackward: NestedScrollMode.SELF_FIRST //向下滑动 自己优先})}
}3. 键盘避让
import { KeyboardAvoidMode } from '@kit.ArkUI'//需要手动引入aboutToAppear(): void {// 设置软键盘弹出时界面的调整策略 setKeyboardAvoidMode// KeyboardAvoidMode.RESIZE是鸿蒙提供的枚举值,表示键盘弹出时自动调整界面布局this.getUIContext().setKeyboardAvoidMode( KeyboardAvoidMode.RESIZE)}
import { KeyboardAvoidMode } from '@kit.ArkUI'//需要手动引入,不会自动引入@Entry
@Component
struct JianPanBiRang {aboutToAppear(): void {// 软键盘弹起避让——压缩模式this.getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.RESIZE)}build() {Column() {Column() {Row({ space: 10 }) {Image($r('app.media.ic_public_arrow_down')).width(20).aspectRatio(1)Text('在干撒')}.width('100%').justifyContent(FlexAlign.Start)Row({ space: 10 }) {Text('敲代码')Image($r('app.media.ic_public_arrow_down')).width(20).aspectRatio(1)}.width('100%').justifyContent(FlexAlign.End)}.layoutWeight(1)TextInput().backgroundColor(Color.Brown)}.height('100%').width('100%').padding(20)}
}4. 跨ability跳转
Ability名称查看位置

4.1. 同一个项目 - ability跳转
import { common } from '@kit.AbilityKit'Button('跳转XXXX')
.onClick(() => {// 1、获取UIAbilityContext应用上下文const ctx = this.getUIContext().getHostContext() as common.UIAbilityContext// 2、唤起其他的ability窗口ctx.startAbility({bundleName: 'com.example.my_base', //应用的包名abilityName: 'ShiPinHao' //ability的名称})})
import { common } from '@kit.AbilityKit'AppStorage.setOrCreate('name', '参数:12')@Entry
@Component
struct WeiXinPage {build() {Column() {Text('微信聊天').fontSize(30).margin({ top: 50 })Button('跳转到视频号').onClick(() => {// 获取UIAbilityContext应用上下文const ctx = this.getUIContext().getHostContext() as common.UIAbilityContext// 唤起其他的ability窗口ctx.startAbility({bundleName: 'com.example.my_base', //应用的包名abilityName: 'ShiPinHao' //ability的名称})})}.height('100%').width('100%')}
}
@Entry
@Component
struct Index {@StorageLink('name')name: string = ''build() {Column({ space: 20 }) {Text('视频号').fontSize(30)Text(this.name).fontSize(30)}.height('100%').width('100%')}
}4.2. 不同项目 - ability跳转
前提:保证两个项目都是运行状态



import { common } from '@kit.AbilityKit'
import { promptAction } from '@kit.ArkUI'@Entry
@Component
struct ChePiaoPage {build() {Column() {Text('12306购票').fontSize(30)Button('去支付宝支付').onClick(async () => {const ctx = this.getUIContext().getHostContext() as common.UIAbilityContextconst res = await ctx.startAbilityForResult({bundleName: 'com.example.my_base02', //需要跳转到的项目 包名abilityName: 'EntryAbility', //需要跳转到的项目 Ability名称moduleName: 'entry', //需要跳转到的项目 模块名称//传递参数parameters: {'money': 299.00}})// 接受参数if (res.want?.parameters) {if (res.want.parameters['success']) {promptAction.openToast({message: '支付成功~',bottom: 300})}}})}.height('100%').width('100%')}
}
import { common } from '@kit.AbilityKit'@Entry
@Component
struct Index {@StorageLink('money')money: number = 0build() {Column() {Text('支付宝界面').fontSize(30)Text('待支付的金额为' + this.money + '元').fontSize(20)Button('输入支付密码').onClick(() => {const ctx = this.getUIContext().getHostContext() as common.UIAbilityContextctx.terminateSelfWithResult({// 返回时,必须写want和resultCode,不可省略want: {bundleName: 'com.example.my_base', //包名abilityName: 'EntryAbility', //ability的模块parameters: { 'success': true }//返回时携带的参数},resultCode: 0//必须写(返回的结果的code)})})}.height('100%').width('100%')}
}