控制页面刷新范围(OpenHarmony)
根据业务需要,有时我们需要触发单个组件的状态更新,有时需要触发部分
根据业务需要,有时我们需要触发单个组件的状态更新,有时需要触发部分或全部组件的状态更新。那么如何控制组件状态刷新的范围呢?本例将为大家提供一种参考方案。
想了解更多关于开源的内容,请访问:
(资料图片仅供参考)
清一色开源基础软件社区
https://ost.51cto.com
在实现页面UI时,业务方需要根据业务逻辑动态更新组件的状态,常见的如在手机桌面长按某个App的图标时,图标背景色、大小等会发生变化。根据业务需要,有时我们需要触发单个组件的状态更新,有时需要触发部分或全部组件的状态更新。那么如何控制组件状态刷新的范围呢?本例将为大家提供一种参考方案。
本例最终效果如下:
本例基于以下环境开发,开发者也可以基于其他适配的版本进行开发:
IDE: DevEco Studio 3.1 ReleaseSDK: Ohos_sdk_public 3.2.12.5(API Version 9 Release)ArkUI可以通过页面的状态数据驱动UI的更新,其UI更新机制可以通过如下表达式来体现:
用户构建了UI模型,其中参数state代表页面组件的运行时状态。当state改变时,UI作为返回结果,也将进行对应的改变刷新。f作为状态管理机制,维护组件运行时的状态变化所带来的UI重新渲染。组件的状态改变可通过状态变量进行控制。
基于上述理论,如果要控制页面的更新范围,我们必须要:定义准确状态变量,并控制状态变量影响的组件范围。
本例中包含8个APP图标,其中涉及5种状态变化,按照局部刷新和全局刷新可分为:
局部刷新(单个卡片变化)点击卡片,卡片背景色变为红色。点击卡片,卡片进行缩放。拖拽卡片,卡片位置变化。全局刷新(全部卡片变化)长按某个卡片,为所有卡片添加删除图标。点击删除图标外的任意地方,删除图标消失。所以处理思路为,控制局部刷新的状态变量在子组件中定义,绑定子组件,控制全局刷新的状态变量在父组件中进行定义,并由父组件传递给所有子组件。如下图:
由于本例重点讲解刷新区域的控制,所以开发步骤会着重讲解相关实现,不相关的内容不做介绍,全量代码可参考完整代码章节。
创建APP卡片组件作为子组件,每个卡片包含文本和删除图标。具体代码如下:
@Componentexport struct AppItem { ... build() { Stack({ alignContent: Alignment.TopEnd }) { Image($r("app.media.ic_public_close")) .height(30) .width(30) .zIndex(2) .offset({ x: -12, y: 12 }) Text(this.data.title) .width(100) .height(100) .fontSize(16) .margin(10) .textAlign(TextAlign.Center) .borderRadius(10) } }}
创建父组件,并在父组件中引用子组件。具体代码如下:
@Entry@Componentstruct Sample { ... build() { Stack({ alignContent: Alignment.Bottom }) { Flex({ wrap: FlexWrap.Wrap }) { // 通过循环渲染加载所有子组件 ForEach(this.items, (item: ItemProps, index: number) => { // 引用App卡片子组件 AppItem({data: this.items[index]}) }, (item: ItemProps) => item.id.toString()) } .width("100%") .height("100%") } .width("100%") .height("100%") .backgroundColor("#ffffff") .margin({ top:50 }) }}
由于卡片背景色变化、卡片缩放、卡片拖拽在触发时都是针对单个卡片的状态变化,所以在卡片子组件中定义相应的状态变量,用来控制单个卡片的状态变化。本例中定义状态变量“data”用来控制卡片拖拽时位置的刷新;定义状态变量”downFlag“用来监听卡片是否被按下,从而控制卡片背景色及缩放状态的更新。具体代码如下:
@Componentexport struct AppItem { // 定义状态变量data,用来控制卡片被拖拽时位置的刷新 @State data: ItemProps = {}; // 定义状态变量downFlag用来监听卡片是否被按下,从而控制卡片背景色及缩放状态的更新 @State downFlag: boolean = false; ... build() { Stack({ alignContent: Alignment.TopEnd }) { Image($r("app.media.ic_public_close")) .height(30) .width(30) .zIndex(2) .offset({ x: -12, y: 12 }) Text(this.data.title) .width(100) .height(100) .fontSize(16) .margin(10) .textAlign(TextAlign.Center) .borderRadius(10) // 根据状态变量downFlag的变化,更新背景色 .backgroundColor(this.downFlag ? "#EEA8AB" : "#86C7CC") // 背景色更新时添加属性动画 .animation({ duration: 500, curve: Curve.Friction }) // 绑定onTouch事件,监听卡片是否被按下,根据不同状态改变downFlag的值 .onTouch((event: TouchEvent) => { if (event.type == TouchType.Down) { this.downFlag = true } else if (event.type == TouchType.Up) { this.downFlag = false } }) } // 根据状态变量downFlag的变化,控制卡片的缩放 .scale(this.downFlag ? { x: 0.8, y: 0.8 } : { x: 1, y: 1 }) // 通过状态变量data的变化,控制卡片位置的更新 .offset({ x: this.data.offsetX, y: this.data.offsetY }) // 拖动触发该手势事件 .gesture( GestureGroup(GestureMode.Parallel, ... PanGesture(this.panOption) .onActionStart((event: GestureEvent) => { console.info("Pan start") }) // 拖动卡片时,改变状态变量data的值 .onActionUpdate((event: GestureEvent) => { this.data.offsetX = this.data.positionX + event.offsetX this.data.offsetY = this.data.positionY + event.offsetY }) .onActionEnd(() => { this.data.positionX = this.data.offsetX this.data.positionY = this.data.offsetY console.info("Pan end") }) ) ) }}
长按卡片,卡片右上角会出现删除图标。
由于所有卡片右上角都会出现删除图标,所以这里需要做全局的刷新。本例在父组件中定义状态变量“deleteVisibility”,在调用子组件时,将其作为参数传递给所有卡片子组件,并且通过@Link装饰器与子组件进行双向绑定,从而可以控制所有卡片子组件中删除图标的更新。
@Entry@Componentstruct Sample { ... // 定义状态变量deleteVisibility,控制App卡片上删除图标的更新 @State deleteVisibility: boolean = false ... build() { Stack({ alignContent: Alignment.Bottom }) { Flex({ wrap: FlexWrap.Wrap }) { // 通过循环渲染加载所有子组件 ForEach(this.items, (item: ItemProps, index: number) => { // 将状态变量deleteVisibility传递给每一个子组件,从而deleteVisibility变化时可以触发所有子组件的更新 AppItem({ deleteVisibility: $deleteVisibility, data: this.items[index], onDeleteClick: this.delete }) }, (item: ItemProps) => item.id.toString()) } .width("100%") .height("100%") } .width("100%") .height("100%") .backgroundColor("#ffffff") .margin({ top:50 }) .onClick(() => { this.deleteVisibility = false }) }
@Componentexport struct AppItem { ... // 定义deleteVisibility状态变量,并通过@Link装饰器与父组件中的同名变量双向绑定,该变量值发生变化时父子组件可双向同步 @Link deleteVisibility: boolean; ... build() { Stack({ alignContent: Alignment.TopEnd }) { // 通过deleteVisibility控制删除图标的隐藏和显示,当deleteVisibility值为true时显示,为false时隐藏 if(this.deleteVisibility){ Image($r("app.media.ic_public_close")) .height(30) .width(30) .zIndex(2) // 控制删除图标的显隐 .visibility(Visibility.Visible) .offset({ x: -12, y: 12 }) .onClick(() => this.onDeleteClick(this.data.id)) }else{ Image($r("app.media.ic_public_close")) .height(30) .width(30) .zIndex(2) .visibility(Visibility.Hidden) .offset({ x: -12, y: 12 }) .onClick(() => this.onDeleteClick(this.data.id)) } ... .gesture( GestureGroup(GestureMode.Parallel, // 识别长按手势 LongPressGesture({ repeat: true }) .onAction((event: GestureEvent) => { if (event.repeat) { // 长按时改变deleteVisibility的值为true,从而更新删除图标为显示状态 this.deleteVisibility = true } console.info("LongPress onAction") }), ... ) ) }}
本例完整代码如下:data.ets文件(数据模型文件)
// data.ets// AppItem组件接口信息export interface ItemProps { id?: number, title?: string, offsetX?: number, // X偏移量 offsetY?: number, // Y偏移量 positionX?: number, // 在X的位置 positionY?: number, // 在Y的位置}// AppItem初始数据export const initItemsData: ItemProps[] = [ { id: 1, title: "APP1", offsetX: 0, offsetY: 0, positionX: 0, positionY: 0 }, { id: 2, title: "APP2", offsetX: 0, offsetY: 0, positionX: 0, positionY: 0 }, { id: 3, title: "APP3", offsetX: 0, offsetY: 0, positionX: 0, positionY: 0 }, { id: 4, title: "APP4", offsetX: 0, offsetY: 0, positionX: 0, positionY: 0 }, { id: 5, title: "APP5", offsetX: 0, offsetY: 0, positionX: 0, positionY: 0 }, { id: 6, title: "APP6", offsetX: 0, offsetY: 0, positionX: 0, positionY: 0 }, { id: 7, title: "APP7", offsetX: 0, offsetY: 0, positionX: 0, positionY: 0 }, { id: 8, title: "APP8", offsetX: 0, offsetY: 0, positionX: 0, positionY: 0 },]
// AppItem.etsimport { ItemProps } from "../model/data";@Componentexport struct AppItem { // 定义状态变量data,用来控制卡片被拖拽时位置的刷新 @State data: ItemProps = {}; // 定义状态变量downFlag用来监听卡片是否被按下,从而控制卡片背景色及缩放状态的更新 @State downFlag: boolean = false; // 定义deleteVisibility状态变量,并通过@Link装饰器与父组件中的同名变量双向绑定,该变量值发生变化时父子组件可双向同步 @Link deleteVisibility: boolean; private onDeleteClick: (id: number) => void; private panOption: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.All }); build() { Stack({ alignContent: Alignment.TopEnd }) { // 通过deleteVisibility控制删除图标的隐藏和显示,当deleteVisibility值为true时显示,为false时隐藏 if(this.deleteVisibility){ Image($r("app.media.ic_public_close")) .height(30) .width(30) .zIndex(2) // 控制删除图标的显隐 .visibility(Visibility.Visible) .offset({ x: -12, y: 12 }) .onClick(() => this.onDeleteClick(this.data.id)) }else{ Image($r("app.media.ic_public_close")) .height(30) .width(30) .zIndex(2) .visibility(Visibility.Hidden) .offset({ x: -12, y: 12 }) .onClick(() => this.onDeleteClick(this.data.id)) } Text(this.data.title) .width(100) .height(100) .fontSize(16) .margin(10) .textAlign(TextAlign.Center) .borderRadius(10) // 根据状态变量downFlag的变化,更新背景色 .backgroundColor(this.downFlag ? "#EEA8AB" : "#86C7CC") // 背景色更新时添加属性动画 .animation({ duration: 500, curve: Curve.Friction }) // 绑定onTouch事件,监听卡片是否被按下,根据不同状态改变downFlag的值 .onTouch((event: TouchEvent) => { if (event.type == TouchType.Down) { this.downFlag = true } else if (event.type == TouchType.Up) { // 手指抬起 this.downFlag = false } }) } // 根据状态变量downFlag的变化,控制卡片的缩放 .scale(this.downFlag ? { x: 0.8, y: 0.8 } : { x: 1, y: 1 }) // 通过状态变量data的变化,控制卡片位置的更新 .offset({ x: this.data.offsetX, y: this.data.offsetY }) // 拖动触发该手势事件 .gesture( GestureGroup(GestureMode.Parallel, // 识别长按手势 LongPressGesture({ repeat: true }) .onAction((event: GestureEvent) => { if (event.repeat) { // 长按时改变deleteVisibility的值为true,从而更新删除图标为显示状态 this.deleteVisibility = true } console.info("LongPress onAction") }), PanGesture(this.panOption) .onActionStart((event: GestureEvent) => { console.info("Pan start") }) // 拖动卡片时,改变状态变量data的值 .onActionUpdate((event: GestureEvent) => { this.data.offsetX = this.data.positionX + event.offsetX this.data.offsetY = this.data.positionY + event.offsetY }) .onActionEnd(() => { this.data.positionX = this.data.offsetX this.data.positionY = this.data.offsetY console.info("Pan end") }) ) ) }}
// Index.etsimport { AppItem } from "../components/MyItem";import { initItemsData } from "../model/data";import { ItemProps } from "../model/data";@Entry@Componentstruct Sample { @State items: ItemProps[] = []; // 定义状态变量deleteVisibility,控制App卡片上删除图标的更新 @State deleteVisibility: boolean = false // 删除指定id组件 private delete = (id: number) => { const index = this.items.findIndex(item => item.id === id); this.items.splice(index, 1); } // 生命周期函数:组件即将出现时调用 aboutToAppear() { this.items = [...initItemsData]; } build() { Stack({ alignContent: Alignment.Bottom }) { Flex({ wrap: FlexWrap.Wrap }) { // 通过循环渲染加载所有子组件 ForEach(this.items, (item: ItemProps, index: number) => { // 将状态变量deleteVisibility传递给每一个子组件,从而deleteVisibility变化时可以触发所有子组件的更新 AppItem({ deleteVisibility: $deleteVisibility, data: this.items[index], onDeleteClick: this.delete }) }, (item: ItemProps) => item.id.toString()) } .width("100%") .height("100%") } .width("100%") .height("100%") .backgroundColor("#ffffff") .margin({ top:50 }) .onClick(() => { // 点击组件,deleteVisibility值变为false,从而隐藏所有卡片的删除图标 this.deleteVisibility = false }) }}
刷新范围一般通过状态变量进行控制,需要厘清状态变量影响的范围,从而当状态变量发生改变时可同步刷新相关的UI区域。
想了解更多关于开源的内容,请访问:
清一色开源基础软件社区
https://ost.51cto.com
关键词:
根据业务需要,有时我们需要触发单个组件的状态更新,有时需要触发部分
关于intel笔记本CPU中超线程与物理核心在性能与功耗上的测试noowood酱
今天来聊聊议服务保障工作总结,会议服务工作包括哪些内容的文章,现在
1、第季节目嘉宾简单资料实际血型:Alex:A型申:A型星座+资料:Alex1979 9 2处座本
1、打开浏览器,输入“身份证查询”2、打开后,就可以看到一款百度应用
6月12日电据美媒11日报道,哥伦比亚坠机事件中幸存的四名儿童已经逐渐
01:32由中共铜仁市碧江区委、铜仁市碧江区人民政府主办、铜仁市碧江区
中国互联网联合辟谣平台根据网上数据监测和网民举报,对5月网络谣言进
美国国土安全部近期宣布以人权为由将2家中国实体增列至“维吾尔强迫劳
成都初中大摇号报名官网:成都招考网上报名官网网址:https: online c
关于小米要进军汽车行业这件事,其实早就不新鲜了。但是,相比于其他“
全国人大常委会特种设备安全法执法检查组举行第二次全体会议---新华社
药师资格证报考时间2023由执业药师考试栏目提供,查找更多考试报名资讯
6月10日,“老人突发脑梗发现医生隐瞒未植入支架”的词条登上社交平台
辽宁省纪检监察机关等6个部门近日联合发布了关于严厉打击“政治骗子”
很不错。福寿满盈年金保险由前海人寿保险公司提供,是一种非常受欢迎的
对于7寸照片的尺寸是多少这个问题感兴趣的朋友应该很多,这个也是目前
一旦愿意相信阴谋,这个世界其实到处都可以是阴谋。编者按:本文来自微
6月9日沪指上涨0 55%,市场两融余额为15992 24亿元,较前一交易日减少8
近期以来,市、县两级教育行政部门组建明察暗访组,全面排查整治违规组