苏州相城区网站建设,WordPress 古腾堡开发,大连警方最新通告,德化县住房和城乡建设局网站1、组件状态管理
1.1、概述
在应用中#xff0c;界面一般都是动态的。界面会根据不同状态展示不一样的效果。
ArkUI作为一种声明式UI#xff0c;具有状态驱动UI更新的特点#xff0c;当用户进行界面交互或有外部事件引起状态改变时#xff0c;状态的变会会触发组件的自动…1、组件状态管理
1.1、概述
在应用中界面一般都是动态的。界面会根据不同状态展示不一样的效果。
ArkUI作为一种声明式UI具有状态驱动UI更新的特点当用户进行界面交互或有外部事件引起状态改变时状态的变会会触发组件的自动更新。这个时候南非要通过一个变量来记录状态。当改变态的时候ArkUI则会自动更新界面中受影响的部分。 ArkUI框架提供了多种管理状态的装饰器来修饰变量使用这些装饰器修饰的变量即称为状态变量。
在组件范围内传递的状态管理常见场景有如下一些
场景装饰器组件内状态管理State从父组件单向同步状态到子组件Prop与父组件双向同步状态Link跨组件层级双向同步状态Provide和Consume 注意在实际应用开发中应用会根据需要封装数据模型。如果需要观察嵌套类对象属性变化需要使用Observed和ObjectLink装饰器。因为上面表格中所说的装饰器只能观察到对象的第一层属性变化。
1.2、State组件内的状态管理
实际开发中由于交互组件的内容呈现可能产生变化。当需要在组件内使用状态来控制UI的不同呈现方式时可以使用State装饰器。
Entry
Component
struct StateTest {private i: number 0;State text: string ;build() {Row() {Column() {Button(切换,{type: ButtonType.Capsule, stateEffect: true}).width(50%).fontColor(Color.White).fontSize(16).margin({bottom:15}).onClick(() {if(this.i % 2 0) {this.text Harmony OS;} else {this.text 鸿蒙系统;}this.i 1;})Text(this.text).fontSize(16).fontWeight(FontWeight.Bold)}.width(100%)}.height(100%)}
}
上面的例子中text被修饰为State那么它就是一个组件内的状态变量当这个值变化时其相应的组件展示也会同时更新。
1.3、Prop从父组件单向同步状态
当子组件中的状态依赖于父组件传递过来时需要使用Prop装饰器Prop修饰的变量可以和其父组件中的状态建立单向同步关系。当父组件中状态变化时该状态值也会更新至Prop修饰的变量对Prop修饰的变量的修改不会影响其父组件中的状态。
// 子组件 sub.ets
Component
export struct sub {Prop text: string;build(){Row(){Column(){Button(修改text值,{type:ButtonType.Capsule, stateEffect: true}).width(50%).margin({bottom:10}).fontSize(16).onClick((){this.text text在子组件中被修改了})Text(this.text).fontSize(16)}.height(300)}.width(100%).justifyContent(FlexAlign.Center)}
}
// 父组件 PropTest.ets
import { sub } from ../components/sub
Entry
Component
struct PropTest {State text:string 父组件中初始值build() {Row() {Column() {Button(在父组件中修改text,{type:ButtonType.Capsule,stateEffect:true}).width(80%).fontSize(16).margin({bottom:10}).onClick((){this.text 父组件中修改text的值;})Text(this.text).fontSize(16).margin({bottom:30})sub({text:this.text});}.width(100%)}.height(100%)}
} 上面的例子在父组件中传递其text值给到子组件的text当在父组件中修改这个值的时候子组件中相应的值也会同步变化但是在子组件中修改这个值时这个修改的结果不会同步到父组件。
Prop修饰的变量是从父组件传递值来初始化的所以在子组件中是不可以做本地初始化的只能接收来自父组件的值。
1.4、Link父子组件双向同步状态
如果父组件状态需要相互绑定进行双向同步时可以使用Link装饰。父亲组件中用于初始化子组件Link变量的必须是在父组件中定义的状态变量。
// 子组件
Component
export struct sub {Link Watch(OnTextChange) text: string ;State Tip: string OnTextChange(){if(this.text.indexOf(父组件) 0) {this.Tip 使用父组件中的值;} else {this.Tip 使用子组件中的值;}}build(){Row(){Column(){Button(修改text值,{type:ButtonType.Capsule, stateEffect: true}).width(50%).margin({bottom:10}).fontSize(16).onClick((){this.text text在子组件中被修改了})Text(this.text).fontSize(16).margin({bottom:30})Text(Tip${this.Tip}).fontSize(16)}.height(300)}.width(100%).justifyContent(FlexAlign.Center)}
}
// 父组件
import { sub } from ../components/sub
Entry
Component
struct PropTest {State text:string 父组件中初始值build() {Row() {Column() {Button(在父组件中修改text,{type:ButtonType.Capsule,stateEffect:true}).width(80%).fontSize(16).margin({bottom:10}).onClick((){this.text 父组件中修改text的值;})Text(this.text).fontSize(16).margin({bottom:30})sub({text:$text});}.width(100%)}.height(100%)}
}
说明:
1、在子组件中使用Link修饰时它就不可以本地化初始化只能通过父组件提供初始值
2、父组件中在给子组件Link修饰变量进行初始化时需要使用$表示传递的是一个引用
3、Watch装饰器其内提供的是一个回调函数它监控变量的变化情况当发生变化时会触发这个回调函数
1.5、Provide和Consume跨组件层级双向同步状态
它们是用于与后代组件的双向数据同步应用于数据在多层级之间的传递场景。
Provide装饰的变量在祖先节点中可以理解为被“提供”给后代的状态变量
Consume装饰的变量是在后代组件中去消费绑定祖先节点提供的变量
相关的特点
Provide装饰的状态变量自动对其所有后代组件可用开发者无需多次在组件之间传递变量后代组件通过Consume去获取Provide提供的变量建立Provide与Consume之间的双向数据同步而State/Link则不能在多层级父子组件之间传递Provide和Consume可以通过相同的变量名或者相同的变量别名绑定变量类型必须相同
// 通过相同的变量名绑定
Provide a: number 0;
Consume a: number;// 通过变量别名绑定
Provide(a) b: number 0;
Consume(a) c: number;
// 后代子组件S2
Component
export struct S2 {Consume a:number;build(){Row(){Column(){Text(S2).fontSize(16).fontWeight(FontWeight.Bold).margin({bottom:15})Text(a ${this.a}).fontSize(16).fontWeight(FontWeight.Bold).margin({bottom:15})Button(后代修改a的值,{type:ButtonType.Capsule,stateEffect:true}).width(40%).onClick(() {this.a 10;})}}.width(100%).justifyContent(FlexAlign.Center)}}
// 后代子组件S1
import { S2 } from ./S2;
Component
export struct S1 {Consume a:number;build(){Row(){Column(){Text(S1).fontSize(20).fontWeight(FontWeight.Bold).margin({bottom:15})Text(a ${this.a}).fontSize(16).fontWeight(FontWeight.Bold).margin({bottom:15})Divider()S2()}}.width(100%).justifyContent(FlexAlign.Center)}}
父组件
import { S1 } from ../components/S1
Entry
Component
struct ProvideTest {Provide a: number 100build() {Row() {Column() {Button(祖先修改a的值, {type:ButtonType.Capsule,stateEffect:true}).width(50%).margin({bottom:15}).onClick(() {this.a 100;})Text(祖先a ${this.a}).fontSize(24).fontWeight(FontWeight.Bold).margin({bottom:20})Divider()S1()}.width(100%)}.height(100%)}
}
2、Video组件
2.1、Video件用法介绍
Video组件的接口靛达形式为
Video(value:{src?: string | Resource, currentProgressRate?:number | string | PlaybackSpeed, previewUri?: string | PixelMap | Resource, controller?: VideoController})
这其中包含四个可选参数srccurrentProgressRatepreviewUri和controller。
src视频播放源的路径支持本地或网络路径如果是网络地址时需要在module.json5中申请网络权限。在使用本地资源播放时可以使用的媒体库管理模块medialibrary来查询公共媒体库中的视频文件。currentProgressRate视频播放倍速其参数类型是number取值支持0.751.01.251.752.0默认是.0 previewUri表示视频未播放时的预览图片路径controller表示视频控制器
注意支持的视频格式mp4,mkv,webm,TS
2.2、Video组件属性
Video支持组件的尺寸设置、位置设置等通用属性外Video还支持是否静音、是否自动播放、控制栏是否显示、视频显示模式及单个视频是否循环播放五个私有属性。
muted参数类型为boolean表示是否静音默认值是false
autoPlay参数类型为boolean表示是否自动播放默认值是false
controls参数类型为boolean控制视频播放的控制栏是否显示默认值是true
objectFit参数类型为ImageFit设置视频显示模式。默认值是Cover
objectFit中显示模式可选值有Contain,Cover,Auto,Fill,ScaleDown,None
默认情况一使用Cover保持宽高比进行缩小或放大使用图片两边都大于或等于显示边界
loop参数类型为boolean控制单个视频是否循环播放。默认值是false
2.3、Video组件回调事件
事件名称功能描述onStart(event:() void)播放时触发这个事件onPause(event:() void)暂停时触发这个事件onFinish(event:() void)播放结束时触发这个事件onError(event:() void)播放失败时触发这个事件onPrepared(callback:(event?:{duration:number}) void)视频准备完成时触发这个事件通过duration可以获取视频时长sonSeeking(callback:(event?:{time:number}) void)操作进度条过程时上报时间信息单位为sonSeeked(callback:(event?:{time:number}) void)操作进度条完成后上报时间信息单位为sonUpdate(callback:(event?:{time:number}) void)播放进度变化时触发这个事件单位为s,更新时间间隔为250msonFullscreenChange(callback:(event?:{fullscreen:boolean}) void)在全屏和非全屏播放状态之间切换时触发这个事件 2.4、自定义控制器
Video组件的原生控制器样式相对固定当需要对其做一些特殊的显示时则可能无法满足此时则可以自下义控制器。
可以使用Row容器实现整理体的布局Text组件来显示起始时间和视频总时长最后通过Slider组件来实现视频进度条的效果
Component
export struct VidoSlider {...build() {Row(...) {Image(...)Text(...)Slider(...)Text(...)}...}
}
3、弹窗
在日常使用应用时在做一些风险或敏感操作时应用会给出一个弹框提示提示用户是否需要执行这些风险操作。
弹窗是一种模态框常用来提示用户当前需要关注的信息或操作。由于是模态的用户无法操作其它界面内容。在非必要的情况下不推荐使用弹窗这会打断用户交互的过程。
ArkUI提供了两类弹窗
确认类比如警告弹窗 AlertDialog选择类包含文本选择窗TextPickerDialog、日期选择窗DatePickerDialog、时间滑动选择窗TimePickerDialog...
除了上述的一些弹框如不满足业务上的需求还可以自定义弹窗CustomDialog
3.1、警告窗
AlertDialog它由三部分组件
标题可选择内容显示提示信息操作按钮用户做确认或取消等操作 Entry
Component
struct DialogTest {build() {Row() {Column() {Button(点击显示弹窗,{type:ButtonType.Capsule, stateEffect:true}).width(50%).fontSize(16).onClick(() {AlertDialog.show({title: 提示, // 标题message: 确定要删除所选择的记录?, // 内容autoCancel: false, // 点击遮罩层是否关闭弹窗alignment: DialogAlignment.Bottom, // 弹窗在竖直方向的对齐方式offset: {dx: 0, dy: -20}, // 弹窗相对alignment位置的偏移量primaryButton: {value: 取消,action: () {console.info(点击了弹窗的取消按钮);}},secondaryButton: {value: 删除,fontColor: #D94838,action: () {console.info(点击了弹窗的删除按钮);}},cancel: () {console.info(点击遮罩层关闭dailog时回调);}})})}.width(100%)}.height(100%)}
} 上面这个弹框中有两个按钮也可以构建只包含一个按钮的确认弹框这个时候使用confirm响应和按钮回调
Entry
Component
struct DialogTest {build() {Row() {Column() {Button(点击显示弹窗,{type:ButtonType.Capsule, stateEffect:true}).width(50%).fontSize(16).onClick(() {AlertDialog.show({title: 提示, // 标题message: 确定要删除所选择的记录?, // 内容autoCancel: false, // 点击遮罩层是否关闭弹窗alignment: DialogAlignment.Bottom, // 弹窗在竖直方向的对齐方式offset: {dx: 0, dy: -20}, // 弹窗相对alignment位置的偏移量/*primaryButton: {value: 取消,action: () {console.info(点击了弹窗的取消按钮);}},secondaryButton: {value: 删除,fontColor: #D94838,action: () {console.info(点击了弹窗的删除按钮);}},*/confirm: {value: 确认,fontColor: Color.Blue,action: () {console.info(点击了确认按钮);}},cancel: () {console.info(点击遮罩层关闭dailog时回调);}})})}.width(100%)}.height(100%)}
}
3.2、选择类弹窗
选择类弹窗用于方便用户选择相关数据
3.2.1、文本选择弹窗
TextPickerDialog它是文本滑动选择器弹窗根据指定的选择范围创建文本选择器展示在弹窗上。
Entry
Component
struct TextPickerTest {State text: string State index: number 0;private lans: string[] [C,C,Java,Typescript,ArkUI]build() {Column() {Text(你的选择是${this.text}).fontSize(18).fontWeight(FontWeight.Bold).fontColor(#4169E1).margin({bottom:15})Button(请选择语言, {type:ButtonType.Capsule,stateEffect:true}).margin({bottom:15}).width(50%).onClick(() {TextPickerDialog.show({range: this.lans, // 设置文本选择器的选择范围selected: this.index, // 设置初始选中项的索引值onAccept: (value: TextPickerResult) { // 点击弹窗中的“确定”按钮时触发该回调this.text value.value;this.index value.index;console.info(TextPickerDialog:onAccept() JSON.stringify(value));},onCancel: () { // 点击弹窗中的“取消”按钮时触发该回调console.info(TextPickerDialog:onCancel());},onChange: (value: TextPickerResult) { // 滑动弹窗中的选择器使当前选中项改变时触发该回调console.info(TextPickerDialog:onChange JSON.stringify(value))}})})}.width(100%).height(100%).justifyContent(FlexAlign.Center)}
}
3.2.2、日期选择弹窗
DatePickerDialog它是日期滑动选择器弹窗根据指定的日期范围创建日期滑动选择器展示在弹窗上。
Entry
Component
struct DatePickerTest {State selectedDate: string build() {Row() {Column() {Text(你选择的日期是:${this.selectedDate}).fontSize(18).fontWeight(FontWeight.Bold).fontColor(#4169E1).margin({ bottom: 15 })Button(选择日期, { type: ButtonType.Capsule, stateEffect: true }).width(50%).margin({ bottom: 15 }).onClick(() {DatePickerDialog.show({start: new Date(1900-1-1), // 设置选择器的起始日期end: new Date(2023-12-31), // 设置选择器的结束日期selected: this.selectedDate ? new Date() : new Date(this.selectedDate), // 设置当前选中的日期lunar: false,onAccept: (value: DatePickerResult) { // 点击弹窗中的“确定”按钮时触发该回调this.selectedDate ${value.year}-${value.month 1}-${value.day}console.info(DatePickerDialog:onAccept() JSON.stringify(value))},onCancel: () { // 点击弹窗中的“取消”按钮时触发该回调console.info(DatePickerDialog:onCancel())},onChange: (value: DatePickerResult) { // 滑动弹窗中的滑动选择器使当前选中项改变时触发该回调console.info(DatePickerDialog:onChange() JSON.stringify(value))}})})}.width(100%)}.height(100%)}
}
3.3、自定义弹窗
在自定义弹窗中可以自定义弹窗内容用来构建丰富的弹窗界面。
自定义弹窗可以通过装饰器CustomDialog定义组件来实现然后结合CustomDialogController来控制自定义弹窗显示和隐藏。
在resources/base/element/下新增json文件stringarray.json
{strarray: [{name: hobbies_data,value: [{value: Soccer},{value: Badminton},{value: Travelling}]}]
}
同步在en_US,zh_CN目录下也需要新增
ets目录下新增目录viewmodel目录并在其下新增一个HobbyBean的数据结构
export default class HobbyBean {label: string;isChecked: boolean;constructor(label:string, isChecked:boolean) {this.label label;this.isChecked isChecked}
}
ets目录下新增目录components,并在其下新增CustomDialogWidget.ets
import HobbyBean from ../viewmodel/HobbyBean
CustomDialog
export struct CustomDialogWidget {State hobbyBeans: HobbyBean[] [];Link hobbies: string;private controller: CustomDialogController;aboutToAppear(){let context: Context getContext(this);let manager context.resourceManager;manager.getStringArrayValue($r(app.strarray.hobbies_data),(error, hobbyResult){hobbyResult.forEach((hobbyItem:string) {let hobbyBean new HobbyBean(hobbyItem,false);this.hobbyBeans.push(hobbyBean);})})}setHobbiesValue(hobbyBeans: HobbyBean[]) {let hobbiesText: string ;hobbiesText hobbyBeans.filter((isCheckItem: HobbyBean) isCheckItem?.isChecked).map((checkedItem:HobbyBean) {return checkedItem.label;}).join(,);this.hobbies hobbiesText;}build(){Column(){Text(兴趣爱好).fontSize(16).fontWeight(FontWeight.Bold).margin({bottom:10}).textAlign(TextAlign.Start)List() {ForEach(this.hobbyBeans,(itemHobby:HobbyBean) {ListItem(){Row(){Text(itemHobby.label).fontSize(14)Toggle({type: ToggleType.Checkbox,isOn:false}).onChange((isCheck){itemHobby.isChecked isCheck;})}}},itemHobby itemHobby.label)}Row() {Button(取消).onClick(() {this.controller.close();}).width(40%)Button(确定).onClick(() {this.setHobbiesValue(this.hobbyBeans);this.controller.close();}).width(40%)}}.width(95%)}
}
pages目录下新增一个页面CustomDialogTest
import { CustomDialogWidget } from ../components/CustomDialogWidget
import HobbyBean from ../viewmodel/HobbyBean;
Entry
Component
struct CustomDialogTest {State hobbies:string ;customDialogController: CustomDialogController new CustomDialogController({builder: CustomDialogWidget({hobbies:$hobbies}),alignment: DialogAlignment.Bottom,customStyle: true,offset: { dx: 0,dy: -20 }});setHobbiesValue(hobbyArray: HobbyBean[]) {}build() {Row() {Column(){Text(this.hobbies).fontSize(16).margin({bottom:15})Button(点击打开).onClick((){this.customDialogController.open();})}.width(100%)}.height(100%)}
}