作者归档:beiyu
HarmonyOS动画
属性动画
animateTo
1 |
animateTo(value: AnimateParam, event: () => void): void |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
import { curves } from '@kit.ArkUI'; @Entry @Component struct AnimateToDemo { @State animate: boolean = false; // 第一步: 声明相关状态变量 @State rotateValue: number = 0; // 组件一旋转角度 @State translateX: number = 0; // 组件二偏移量 @State opacityValue: number = 1; // 组件二透明度 // 第二步:将状态变量设置到相关可动画属性接口 build() { Row() { // 组件一 Column() { } .rotate({ angle: this.rotateValue }) .backgroundColor('#317AF7') .justifyContent(FlexAlign.Center) .width(100) .height(100) .borderRadius(30) .onClick(() => { this.getUIContext()?.animateTo({ curve: curves.springMotion() }, () => { this.animate = !this.animate; // 第三步:闭包内通过状态变量改变UI界面 // 这里可以写任何能改变UI的逻辑比如数组添加,显隐控制,系统会检测改变后的UI界面与之前的UI界面的差异,对有差异的部分添加动画 // 组件一的rotate属性发生变化,所以会给组件一添加rotate旋转动画 this.rotateValue = this.animate ? 90 : 0; // 组件二的透明度发生变化,所以会给组件二添加透明度的动画 this.opacityValue = this.animate ? 0.6 : 1; // 组件二的translate属性发生变化,所以会给组件二添加translate偏移动画 this.translateX = this.animate ? 50 : 0; }) }) // 组件二 Column() { } .justifyContent(FlexAlign.Center) .width(100) .height(100) .backgroundColor('#D94838') .borderRadius(30) .opacity(this.opacityValue) .translate({ x: this.translateX }) } .width('100%') .height('100%') .justifyContent(FlexAlign.Center) } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
import { curves } from '@kit.ArkUI' @Entry @Component struct Index { @State animate: boolean = false @State rotateValue: number = 0 @State translateX: number = 0 @State opacityValue: number = 1 build() { Column() { Row() .width(100) .height(100) .borderRadius(30) .backgroundColor('#317AF7') .rotate({ angle: this.rotateValue }) .onClick(() => { this.getUIContext()?.animateTo({ curve: curves.springMotion() }, () => { this.animate = !this.animate this.rotateValue = this.animate ? 90 : 0 this.translateX = this.animate ? 50 : 0 this.opacityValue = this.animate ? 0.6 : 1 }) }) Row() .width(100) .height(100) .borderRadius(30) .backgroundColor('#D94838') .opacity(this.opacityValue) .translate({ x: this.translateX }) } .width('100%') .height('100%') .justifyContent(FlexAlign.Center) } } |
animation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
import { curves } from '@kit.ArkUI'; @Entry @Component struct AnimationDemo { @State animate: boolean = false; // 第一步: 声明相关状态变量 @State rotateValue: number = 0; // 组件一旋转角度 @State translateX: number = 0; // 组件二偏移量 @State opacityValue: number = 1; // 组件二透明度 // 第二步:将状态变量设置到相关可动画属性接口 build() { Row() { // 组件一 Column() { } .opacity(this.opacityValue) .rotate({ angle: this.rotateValue }) // 第三步:通过属性动画接口开启属性动画 .animation({ curve: curves.springMotion() }) .backgroundColor('#317AF7') .justifyContent(FlexAlign.Center) .width(100) .height(100) .borderRadius(30) .onClick(() => { this.animate = !this.animate; // 第四步:闭包内通过状态变量改变UI界面 // 这里可以写任何能改变UI的逻辑比如数组添加,显隐控制,系统会检测改变后的UI界面与之前的UI界面的差异,对有差异的部分添加动画 // 组件一的rotate属性发生变化,所以会给组件一添加rotate旋转动画 this.rotateValue = this.animate ? 90 : 0; // 组件二的translate属性发生变化,所以会给组件二添加translate偏移动画 this.translateX = this.animate ? 50 : 0; // 父组件column的opacity属性有变化,会导致其子节点的透明度也变化,所以这里会给column和其子节点的透明度属性都加动画 this.opacityValue = this.animate ? 0.6 : 1; }) // 组件二 Column() { } .justifyContent(FlexAlign.Center) .width(100) .height(100) .backgroundColor('#D94838') .borderRadius(30) .opacity(this.opacityValue) .translate({ x: this.translateX }) .animation({ curve: curves.springMotion() }) } .width('100%') .height('100%') .justifyContent(FlexAlign.Center) } } |
自定义属性动画
@AnimatableExtend
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
// 第一步:使用@AnimatableExtend装饰器,自定义可动画属性接口 @AnimatableExtend(Text) function animatableWidth(width: number) { .width(width) // 调用系统属性接口,逐帧回调函数每帧修改可动画属性的值,实现逐帧布局的效果。 } @Entry @Component struct AnimatablePropertyExample { @State textWidth: number = 80; build() { Column() { Text("AnimatableProperty") .animatableWidth(this.textWidth)// 第二步:将自定义可动画属性接口设置到组件上 .animation({ duration: 2000, curve: Curve.Ease }) // 第三步:为自定义可动画属性接口绑定动画 Button("Play") .onClick(() => { this.textWidth = this.textWidth == 80 ? 160 : 80; // 第四步:改变自定义可动画属性的参数,产生动画 }) } .width("100%") .height('100%') .justifyContent(FlexAlign.Center) .padding(10) } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
declare type Point = number[]; // 定义可动画属性接口的参数类型,实现AnimatableArithmetic<T>接口中加法、减法、乘法和判断相等函数 class PointClass extends Array<number> { constructor(value: Point) { super(value[0], value[1]) } add(rhs: PointClass): PointClass { let result: Point = new Array<number>() as Point; for (let i = 0; i < 2; i++) { result.push(rhs[i] + this[i]) } return new PointClass(result); } subtract(rhs: PointClass): PointClass { let result: Point = new Array<number>() as Point; for (let i = 0; i < 2; i++) { result.push(this[i] - rhs[i]); } return new PointClass(result); } multiply(scale: number): PointClass { let result: Point = new Array<number>() as Point; for (let i = 0; i < 2; i++) { result.push(this[i] * scale) } return new PointClass(result); } } // 定义可动画属性接口的参数类型,实现AnimatableArithmetic<T>接口中加法、减法、乘法和判断相等函数 // 模板T支持嵌套实现AnimatableArithmetic<T>的类型 class PointVector extends Array<PointClass> implements AnimatableArithmetic<Array<Point>> { constructor(initialValue: Array<Point>) { super(); if (initialValue.length) { initialValue.forEach((p: Point) => this.push(new PointClass(p))) } } // implement the IAnimatableArithmetic interface plus(rhs: PointVector): PointVector { let result = new PointVector([]); const len = Math.min(this.length, rhs.length) for (let i = 0; i < len; i++) { result.push(this[i].add(rhs[i])) } return result; } subtract(rhs: PointVector): PointVector { let result = new PointVector([]); const len = Math.min(this.length, rhs.length) for (let i = 0; i < len; i++) { result.push(this[i].subtract(rhs[i])) } return result; } multiply(scale: number): PointVector { let result = new PointVector([]); for (let i = 0; i < this.length; i++) { result.push(this[i].multiply(scale)) } return result; } equals(rhs: PointVector): boolean { if (this.length !== rhs.length) { return false; } for (let index = 0, size = this.length; index < size; ++index) { if (this[index][0] !== rhs[index][0] || this[index][1] !== rhs[index][1]) { return false; } } return true; } } // 自定义可动画属性接口 @AnimatableExtend(Polyline) function animatablePoints(points: PointVector) { .points(points) } @Entry @Component struct AnimatedShape { squareStartPointX: number = 75; squareStartPointY: number = 25; squareWidth: number = 150; squareEndTranslateX: number = 50; squareEndTranslateY: number = 50; @State pointVec1: PointVector = new PointVector([ [this.squareStartPointX, this.squareStartPointY], [this.squareStartPointX + this.squareWidth, this.squareStartPointY], [this.squareStartPointX + this.squareWidth, this.squareStartPointY + this.squareWidth], [this.squareStartPointX, this.squareStartPointY + this.squareWidth] ]); @State pointVec2: PointVector = new PointVector([ [this.squareStartPointX + this.squareEndTranslateX, this.squareStartPointY + this.squareStartPointY], [this.squareStartPointX + this.squareWidth + this.squareEndTranslateX, this.squareStartPointY + this.squareStartPointY], [this.squareStartPointX + this.squareWidth, this.squareStartPointY + this.squareWidth], [this.squareStartPointX, this.squareStartPointY + this.squareWidth] ]); @State color: Color = Color.Green; @State fontSize: number = 20.0; @State polyline1Vec: PointVector = this.pointVec1; @State polyline2Vec: PointVector = this.pointVec2; build() { Row() { Polyline() .width(300) .height(200) .backgroundColor("#0C000000") .fill('#317AF7') .animatablePoints(this.polyline1Vec) .animation({ duration: 2000, delay: 0, curve: Curve.Ease }) .onClick(() => { if (this.polyline1Vec.equals(this.pointVec1)) { this.polyline1Vec = this.pointVec2; } else { this.polyline1Vec = this.pointVec1; } }) } .width('100%').height('100%').justifyContent(FlexAlign.Center) } } |
转场动画
出现/消失转场
单个示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
import { curves } from '@kit.ArkUI'; @Entry @Component struct TransitionEffectDemo { @State isPresent: boolean = false; // 第一步,创建TransitionEffect private effect: TransitionEffect = // 创建默认透明度转场效果,并指定了springMotion(0.6, 0.8)曲线 TransitionEffect.OPACITY.animation({ curve: curves.springMotion(0.6, 0.8) }) // 通过combine方法,这里的动画参数会跟随上面的TransitionEffect,也就是springMotion(0.6, 0.8) .combine(TransitionEffect.scale({ x: 0, y: 0 })) // 添加旋转转场效果,这里的动画参数会跟随上面带animation的TransitionEffect,也就是springMotion(0.6, 0.8) .combine(TransitionEffect.rotate({ angle: 90 })) // 添加平移转场效果,这里的动画参数使用指定的springMotion() .combine(TransitionEffect.translate({ y: 150 }).animation({ curve: curves.springMotion() })) // 添加move转场效果,这里的动画参数会跟随上面的TransitionEffect,也就是springMotion() .combine(TransitionEffect.move(TransitionEdge.END)) build() { Stack() { if (this.isPresent) { Column() { Text('ArkUI') .fontWeight(FontWeight.Bold) .fontSize(20) .fontColor(Color.White) } .justifyContent(FlexAlign.Center) .width(150) .height(150) .borderRadius(10) .backgroundColor(0xf56c6c) // 第二步:将转场效果通过transition接口设置到组件 .transition(this.effect) } // 边框 Column() .width(155) .height(155) .border({ width: 5, radius: 10, color: Color.Black }) // 第三步:新增或者删除组件触发转场,控制新增或者删除组件 Button('Click') .margin({ top: 320 }) .onClick(() => { this.isPresent = !this.isPresent; }) } .width('100%') .height('60%') } } |
多个delay示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
const ITEM_COUNTS = 9; const ITEM_COLOR = '#ED6F21'; const INTERVAL = 30; const DURATION = 300; @Entry @Component struct Index1 { @State isGridShow: boolean = false; private dataArray: number[] = new Array(ITEM_COUNTS); aboutToAppear(): void { for (let i = 0; i < ITEM_COUNTS; i++) { this.dataArray[i] = i; } } build() { Stack() { if (this.isGridShow) { Grid() { ForEach(this.dataArray, (item: number, index: number) => { GridItem() { Stack() { Text((item + 1).toString()) } .size({ width: 50, height: 50 }) .backgroundColor(ITEM_COLOR) .transition(TransitionEffect.OPACITY .combine(TransitionEffect.scale({ x: 0.5, y: 0.5 }))// 对每个方格的转场添加delay,实现组件的渐次出现消失效果 .animation({ duration: DURATION, curve: Curve.Friction, delay: INTERVAL * index })) .borderRadius(10) } // 消失时,如果不对方格的所有父控件添加转场效果,则方格的消失转场不会生效 // 此处让方格的父控件在出现消失转场时一直以0.99的透明度显示,使得方格的转场效果不受影响 .transition(TransitionEffect.opacity(0.99)) }, (item: number) => item.toString()) } .columnsTemplate('1fr 1fr 1fr') .rowsGap(15) .columnsGap(15) .size({ width: 180, height: 180 }) // 消失时,如果不对方格的所有父控件添加转场效果,则方格的消失转场不会生效 // 此处让父控件在出现消失转场时一直以0.99的透明度显示,使得方格的转场效果不受影响 .transition(TransitionEffect.opacity(0.99)) } } .size({ width: '100%', height: '100%' }) .onClick(() => { this.getUIContext()?.animateTo({ duration: DURATION + INTERVAL * (ITEM_COUNTS - 1), curve: Curve.Friction }, () => { this.isGridShow = !this.isGridShow; }) }) } } |
导航转场
PageOne.ets简单代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
// PageOne.ets @Entry @Component struct PageOne { @Provide('pathInfos') pathInfos: NavPathStack = new NavPathStack() private listArray: string[] = ['WLAN', 'Bluetooth', 'Personal Hotpot', 'Connect & Share'] build() { Column() { Navigation(this.pathInfos) { ForEach(this.listArray, (item: string) => { Text(item) .onClick(() => { this.pathInfos.pushPathByName(`${item}`, '详情页面参数') }) }) } .title('设置') .mode(NavigationMode.Auto) } } } @Builder export function MyCommonPageBuilder(name: string, param: string) { MyCommonPage({ name, value: param }) } @Component export struct MyCommonPage { pathInfos: NavPathStack = new NavPathStack() name: String = '' @State value: String = '' build() { NavDestination() { Column() { Text(`${this.name}设置页面`) Text(JSON.stringify(this.value)) Button('返回') .onClick(() => { this.pathInfos.pop() }) } } .title(`${this.name}`) .onReady((ctx: NavDestinationContext) => { this.pathInfos = ctx.pathStack }) } } |
PageOne.ets使用@Extend写法代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
@Entry @Component struct PageOne { @Provide('pathInfos') pathInfos: NavPathStack = new NavPathStack() private listArray: string[] = ['WLAN', 'Bluetooth', 'Personal Hotpot', 'Connect & Share'] build() { Column() { Navigation(this.pathInfos) { TextInput({ placeholder: '输入关键字搜索' }) .inputExtend() List({ space: 12, initialIndex: 0 }) { ForEach(this.listArray, (item: string) => { ListItem() { Row() { this.initialLetterBuilder(item.slice(0, 1)) Column() { Text(item) .fontSize(16) } .alignItems(HorizontalAlign.Center) Blank() this.rightArrowBuilder() } .listRowExtend() } .width('100%') .onClick(() => { this.pathInfos.pushPathByName(`${item}`, '详情页面参数') }) }, (item: string): string => item) } .listExtend() } .navigationExtend() } .columnExtend() } @Builder initialLetterBuilder(letter: string) { Row() { Text(letter) .fontColor(Color.White) .fontSize(14) .fontWeight(FontWeight.Bold) } .width(30) .height(30) .backgroundColor('#a8a8a8') .margin({ right: 20 }) .borderRadius(20) .justifyContent(FlexAlign.Center) } @Builder rightArrowBuilder() { Row() .width(12) .height(12) .border({ width: { top: 2, right: 2 }, color: 0xcccccc }) .rotate({ angle: 45 }) } } @Extend(Column) function columnExtend() { .size({ width: '100%', height: '100%' }) .backgroundColor(0xf4f4f5) } @Extend(Navigation) function navigationExtend() { .width('100%') .title('设置') .mode(NavigationMode.Auto) } @Extend(List) function listExtend() { .listDirection(Axis.Vertical) .edgeEffect(EdgeEffect.Spring) .sticky(StickyStyle.Header) .chainAnimation(false) .width('100%') } @Extend(Row) function listRowExtend() { .width('90%') .padding(15) .backgroundColor(Color.White) .shadow({ radius: 100, color: '#ededed' }) .borderRadius(15) .alignItems(VerticalAlign.Center) } @Extend(TextInput) function inputExtend() { .width('90%') .height(40) .margin({ bottom: 10 }) } @Builder export function MyCommonPageBuilder(name: string, param: string) { MyCommonPage({ name, value: param }) } @Component export struct MyCommonPage { pathInfos: NavPathStack = new NavPathStack() name: String = '' @State value: String = '' build() { NavDestination() { Column() { Text(`${this.name}设置页面`) .width('100%') .fontSize(20) .fontColor(0x333333) .textAlign(TextAlign.Center) .textShadow({ radius: 2, offsetX: 4, offsetY: 4, color: 0x909399 }) .padding({ top: 30 }) Text(JSON.stringify(this.value)) .width('100%') .fontSize(18) .fontColor(0x666666) .textAlign(TextAlign.Center) .padding({ top: 45 }) Button('返回') .width('50%') .height(40) .margin({ top: 50 }) .onClick(() => { this.pathInfos.pop() }) } .size({ width: '100%', height: '100%' }) } .title(`${this.name}`) .onReady((ctx: NavDestinationContext) => { this.pathInfos = ctx.pathStack }) } } |
PageOne.ets官方代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
//PageOne.ets @Entry @Component struct NavigationDemo { @Provide('pathInfos') pathInfos: NavPathStack = new NavPathStack(); private listArray: Array<string> = ['WLAN', 'Bluetooth', 'Personal Hotpot', 'Connect & Share']; build() { Column() { Navigation(this.pathInfos) { TextInput({ placeholder: '输入关键字搜索' }) .width('90%') .height(40) .margin({ bottom: 10 }) // 通过List定义导航的一级界面 List({ space: 12, initialIndex: 0 }) { ForEach(this.listArray, (item: string) => { ListItem() { Row() { Row() { Text(`${item.slice(0, 1)}`) .fontColor(Color.White) .fontSize(14) .fontWeight(FontWeight.Bold) } .width(30) .height(30) .backgroundColor('#a8a8a8') .margin({ right: 20 }) .borderRadius(20) .justifyContent(FlexAlign.Center) Column() { Text(item) .fontSize(16) .margin({ bottom: 5 }) } .alignItems(HorizontalAlign.Start) Blank() Row() .width(12) .height(12) .margin({ right: 15 }) .border({ width: { top: 2, right: 2 }, color: 0xcccccc }) .rotate({ angle: 45 }) } .borderRadius(15) .shadow({ radius: 100, color: '#ededed' }) .width('90%') .alignItems(VerticalAlign.Center) .padding({ left: 15, top: 15, bottom: 15 }) .backgroundColor(Color.White) } .width('100%') .onClick(() => { this.pathInfos.pushPathByName(`${item}`, '详情页面参数')//将name指定的NaviDestination页面信息入栈,传递的参数为param }) }, (item: string): string => item) } .listDirection(Axis.Vertical) .edgeEffect(EdgeEffect.Spring) .sticky(StickyStyle.Header) .chainAnimation(false) .width('100%') } .width('100%') .mode(NavigationMode.Auto) .title('设置') // 设置标题文字 } .size({ width: '100%', height: '100%' }) .backgroundColor(0xf4f4f5) } } //PageOne.ets @Builder export function MyCommonPageBuilder(name: string, param: string) { MyCommonPage({ name: name, value: param }) } @Component export struct MyCommonPage { pathInfos: NavPathStack = new NavPathStack(); name: String = ''; @State value: String = ''; build() { NavDestination() { Column() { Text(`${this.name}设置页面`) .width('100%') .fontSize(20) .fontColor(0x333333) .textAlign(TextAlign.Center) .textShadow({ radius: 2, offsetX: 4, offsetY: 4, color: 0x909399 }) .padding({ top: 30 }) Text(`${JSON.stringify(this.value)}`) .width('100%') .fontSize(18) .fontColor(0x666666) .textAlign(TextAlign.Center) .padding({ top: 45 }) Button('返回') .width('50%') .height(40) .margin({ top: 50 }) .onClick(() => { //弹出路由栈栈顶元素,返回上个页面 this.pathInfos.pop(); }) } .size({ width: '100%', height: '100%' }) }.title(`${this.name}`) .onReady((ctx: NavDestinationContext) => { //NavDestinationContext获取当前所在的页面栈 this.pathInfos = ctx.pathStack; }) } } |
PageTwo.ets简单代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
//PageTwo.ets @Builder export function MySharePageBuilder(name: string, param: string) { MySharePage({ name: name }) } @Component export struct MySharePage { pathInfos: NavPathStack = new NavPathStack(); name: String = ''; private listArray: Array<string> = ['Projection', 'Print', 'VPN', 'Private DNS', 'NFC']; build() { NavDestination() { Column() { ForEach(this.listArray, (item: string) => { Text(item) .onClick(() => { this.pathInfos.pushPathByName(`${item}`, '页面设置参数') }) }, (item: string): string => item) } } .title(`${this.name}`) .onReady((ctx: NavDestinationContext) => { //NavDestinationContext获取当前所在的页面栈 this.pathInfos = ctx.pathStack; }) } } |
PageTwo.ets官方代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
//PageTwo.ets @Builder export function MySharePageBuilder(name: string, param: string) { MySharePage({ name: name }) } @Component export struct MySharePage { pathInfos: NavPathStack = new NavPathStack(); name: String = ''; private listArray: Array<string> = ['Projection', 'Print', 'VPN', 'Private DNS', 'NFC']; build() { NavDestination() { Column() { List({ space: 12, initialIndex: 0 }) { ForEach(this.listArray, (item: string) => { ListItem() { Row() { Row() { Text(`${item.slice(0, 1)}`) .fontColor(Color.White) .fontSize(14) .fontWeight(FontWeight.Bold) } .width(30) .height(30) .backgroundColor('#a8a8a8') .margin({ right: 20 }) .borderRadius(20) .justifyContent(FlexAlign.Center) Column() { Text(item) .fontSize(16) .margin({ bottom: 5 }) } .alignItems(HorizontalAlign.Start) Blank() Row() .width(12) .height(12) .margin({ right: 15 }) .border({ width: { top: 2, right: 2 }, color: 0xcccccc }) .rotate({ angle: 45 }) } .borderRadius(15) .shadow({ radius: 100, color: '#ededed' }) .width('90%') .alignItems(VerticalAlign.Center) .padding({ left: 15, top: 15, bottom: 15 }) .backgroundColor(Color.White) } .width('100%') .onClick(() => { this.pathInfos.pushPathByName(`${item}`, '页面设置参数') }) }, (item: string): string => item) } .listDirection(Axis.Vertical) .edgeEffect(EdgeEffect.Spring) .sticky(StickyStyle.Header) .width('100%') } .size({ width: '100%', height: '100%' }) }.title(`${this.name}`) .onReady((ctx: NavDestinationContext) => { //NavDestinationContext获取当前所在的页面栈 this.pathInfos = ctx.pathStack; }) } } |
工程配置文件module.json5中配置 {“routerMap”: “$profile:route_map”}。
route_map.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
{ "routerMap": [ { "name": "WLAN", "pageSourceFile": "src/main/ets/pages/PageOne.ets", "buildFunction": "MyCommonPageBuilder" }, { "name": "Bluetooth", "pageSourceFile": "src/main/ets/pages/PageOne.ets", "buildFunction": "MyCommonPageBuilder" }, { "name": "Personal Hotpot", "pageSourceFile": "src/main/ets/pages/PageOne.ets", "buildFunction": "MyCommonPageBuilder" }, { "name": "Connect & Share", "pageSourceFile": "src/main/ets/pages/PageTwo.ets", "buildFunction": "MySharePageBuilder" }, { "name": "Projection", "pageSourceFile": "src/main/ets/pages/PageOne.ets", "buildFunction": "MyCommonPageBuilder" }, { "name": "Print", "pageSourceFile": "src/main/ets/pages/PageOne.ets", "buildFunction": "MyCommonPageBuilder" }, { "name": "VPN", "pageSourceFile": "src/main/ets/pages/PageOne.ets", "buildFunction": "MyCommonPageBuilder" }, { "name": "Private DNS", "pageSourceFile": "src/main/ets/pages/PageOne.ets", "buildFunction": "MyCommonPageBuilder" }, { "name": "NFC", "pageSourceFile": "src/main/ets/pages/PageOne.ets", "buildFunction": "MyCommonPageBuilder" } ] } |
模态转场
使用bindContentCover构建全屏模态转场效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
import { curves } from '@kit.ArkUI'; @Entry @Component struct BindContentCoverDemo { // 第一步:定义全屏模态转场效果bindContentCover // 模态转场控制变量 @State isPresent: boolean = false; // 第二步:定义模态展示界面 // 通过@Builder构建模态展示界面 @Builder MyBuilder() { Column() { Button('关闭') .onClick(() => { this.isPresent = !this.isPresent; }) } .size({ width: '100%', height: '100%' }) .justifyContent(FlexAlign.Center) .backgroundColor(0xf5f5f5) // 通过转场动画实现出现消失转场动画效果 .transition(TransitionEffect.translate({ y: 1000 }).animation({ curve: curves.springMotion(0.6, 0.8) })) } build() { Column() { Button('弹出全屏模态组件') .bindContentCover(this.isPresent, this.MyBuilder(), { modalTransition: ModalTransition.DEFAULT, onDisappear: () => { if (this.isPresent) { this.isPresent = !this.isPresent; } } }) .onClick(() => { // 第三步:通过模态接口调起模态展示界面,通过转场动画或者共享元素动画去实现对应的动画效果 // 改变状态变量,显示模态界面 this.isPresent = !this.isPresent; }) } } } |
使用bindSheet构建半模态转场效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
@Entry @Component struct BindSheetDemo { // 半模态转场显示隐藏控制 @State isShowSheet: boolean = false; // 通过@Builder构建半模态展示界面 @Builder mySheet() { Column() { Text('内容') } .width('100%') .height('100%') .backgroundColor(Color.White) } build() { Column() { Button('使用bindSheet构建半模态转场效果')// 通过选定的半模态接口,绑定模态展示界面,style中包含两个参数,一个是设置半模态的高度,不设置时默认高度是Large,一个是是否显示控制条DragBar,默认是true显示控制条,通过onDisappear控制状态变量变换。 .bindSheet(this.isShowSheet, this.mySheet(), { height: 300, dragBar: false, onDisappear: () => { this.isShowSheet = !this.isShowSheet; } }) .onClick(() => { this.isShowSheet = !this.isShowSheet; }) } .width('100%') } } |
使用bindMenu实现菜单弹出效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
class BMD { value: ResourceStr = '' action: () => void = () => { } } @Entry @Component struct BindMenuDemo { // 第一步: 定义一组数据用来表示菜单按钮项 @State items: BMD[] = [ { value: '菜单项1', action: () => { console.info('handle Menu1 select') } }, { value: '菜单项2', action: () => { console.info('handle Menu2 select') } }, ] build() { Column() { Button('click') .backgroundColor(0x409eff) .borderRadius(5)// 第二步: 通过bindMenu接口将菜单数据绑定给元素 .bindMenu(this.items) } .justifyContent(FlexAlign.Center) .width('100%') .height(437) } } |
使用bindContextMenu实现菜单弹出效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
@Entry @Component struct BindContextMenuDemo { // 通过@Builder构建自定义菜单项 @Builder myMenu() { Column() { Text('Menu1') .height(40) Text('Menu2') .height(40) } .width(140) .backgroundColor(0xf1f1f1) } build() { Column() { Button('长按或右键点击') .bindContextMenu(this.myMenu, ResponseType.LongPress) } .width('100%') .alignItems(HorizontalAlign.Center) } } |
使用bindPopUp实现气泡弹窗效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
@Entry @Component struct BindPopupDemo { // 第一步:定义变量控制弹窗显示 @State customPopup: boolean = false; // 第二步:popup构造器定义弹框内容 @Builder popupBuilder() { Column({ space: 2 }) { Row().width(64) .height(64) .backgroundColor(0x409eff) Text('Popup') .fontSize(10) .fontColor(Color.White) } .justifyContent(FlexAlign.SpaceAround) .width(100) .height(100) .padding(5) } build() { Column() { Button('click')// 第四步:创建点击事件,控制弹窗显隐 .onClick(() => { this.customPopup = !this.customPopup; }) .backgroundColor(0xf56c6c)// 第三步:使用bindPopup接口将弹窗内容绑定给元素 .bindPopup(this.customPopup, { builder: this.popupBuilder, placement: Placement.Top, maskColor: 0x33000000, popupColor: 0xf56c6c, enableArrow: true, onStateChange: (e) => { if (!e.isVisible) { this.customPopup = false; } } }) } .justifyContent(FlexAlign.Center) .width('100%') .height(437) } } |
使用if实现模态转场
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
@Entry @Component struct ModalTransitionWithIf { // 第一步:定义状态变量控制页面显示 @State isShowShare: boolean = false; private shareFunc(): void { this.getUIContext()?.animateTo({ duration: 500 }, () => { this.isShowShare = !this.isShowShare; }) } build() { // 第二步:定义Stack布局显示当前页面和模态页面 Stack() { Column() { Button('click').onClick(() => { this.shareFunc(); }) } .width('100%') .height('100%') // 第三步:在if中定义模态页面,显示在最上层,通过if控制模态页面出现消失 if (this.isShowShare) { Column() { Button('Close') .onClick(() => { this.shareFunc(); }) } .width('100%') .height('100%') .backgroundColor(0xffffff) // 第四步:定义模态页面出现消失转场方式 .transition(TransitionEffect.OPACITY .combine(TransitionEffect.translate({ x: '100%' })) .combine(TransitionEffect.scale({ x: 0.95, y: 0.95 }))) } } } } |
共享元素转场
不新建容器并直接变化原容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
class PostData { avatar: Resource = $r('app.media.app_icon'); name: string = ''; message: string = ''; images: Resource[] = []; } @Entry @Component struct Index { @State isExpand: boolean = false; @State @Watch('onItemClicked') selectedIndex: number = -1; private allPostData: PostData[] = [ { avatar: $r('app.media.app_icon'), name: 'Alice', message: '天气晴朗', images: [$r('app.media.app_icon'), $r('app.media.app_icon')] }, { avatar: $r('app.media.app_icon'), name: 'Bob', message: '你好世界', images: [$r('app.media.app_icon')] }, { avatar: $r('app.media.app_icon'), name: 'Carl', message: '万物生长', images: [$r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon')] }]; private onItemClicked(): void { if (this.selectedIndex < 0) { return; } this.getUIContext()?.animateTo({ duration: 350, curve: Curve.Friction }, () => { this.isExpand = !this.isExpand; }); } build() { Column({ space: 20 }) { ForEach(this.allPostData, (postData: PostData, index: number) => { // 当点击了某个post后,会使其余的post消失下树 if (!this.isExpand || this.selectedIndex === index) { Column() { Post({ data: postData, selecteIndex: this.selectedIndex, index: index }) } .width('100%') // 对出现消失的post添加透明度转场和位移转场效果 .transition(TransitionEffect.OPACITY .combine(TransitionEffect.translate({ y: index < this.selectedIndex ? -250 : 250 })) .animation({ duration: 350, curve: Curve.Friction })) } }, (postData: PostData, index: number) => index.toString()) } .size({ width: '100%', height: '100%' }) .backgroundColor('#40808080') } } @Component export default struct Post { @Link selecteIndex: number; @Prop data: PostData; @Prop index: number; @State itemHeight: number = 250; @State isExpand: boolean = false; @State expandImageSize: number = 100; @State avatarSize: number = 50; build() { Column({ space: 20 }) { Row({ space: 10 }) { Image(this.data.avatar) .size({ width: this.avatarSize, height: this.avatarSize }) .borderRadius(this.avatarSize / 2) .clip(true) Text(this.data.name) } .justifyContent(FlexAlign.Start) Text(this.data.message) Row({ space: 15 }) { ForEach(this.data.images, (imageResource: Resource, index: number) => { Image(imageResource) .size({ width: this.expandImageSize, height: this.expandImageSize }) }, (imageResource: Resource, index: number) => index.toString()) } if (this.isExpand) { Column() { Text('评论区')// 对评论区文本添加出现消失转场效果 .transition(TransitionEffect.OPACITY .animation({ duration: 350, curve: Curve.Friction })) .padding({ top: 10 }) } .transition(TransitionEffect.asymmetric( TransitionEffect.opacity(0.99) .animation({ duration: 350, curve: Curve.Friction }), TransitionEffect.OPACITY.animation({ duration: 0 }) )) .size({ width: '100%' }) } } .backgroundColor(Color.White) .size({ width: '100%', height: this.itemHeight }) .alignItems(HorizontalAlign.Start) .padding({ left: 10, top: 10 }) .onClick(() => { this.selecteIndex = -1; this.selecteIndex = this.index; this.getUIContext()?.animateTo({ duration: 350, curve: Curve.Friction }, () => { // 对展开的post做宽高动画,并对头像尺寸和图片尺寸加动画 this.isExpand = !this.isExpand; this.itemHeight = this.isExpand ? 780 : 250; this.avatarSize = this.isExpand ? 75 : 50; this.expandImageSize = (this.isExpand && this.data.images.length > 0) ? (360 - (this.data.images.length + 1) * 15) / this.data.images.length : 100; }) }) } } |
HarmonyOS写法示例
HarmonyOS装饰器:@Watch、@Observed、@ObjectLink
js按引用传递、按值传递
在 JavaScript 中,按值传递和按引用传递的概念很重要。基本类型(如数字、字符串、布尔值)是按值传递的,而对象类型(如数组、对象)是按引用传递的。
1. 按值传递(Pass by Value)
对于基本数据类型(如number
、string
、boolean
、undefined
、null
、symbol
),JavaScript 是按值传递的。即,在函数中传递这些类型的变量时,传递的是它们的值的副本,不会影响原始变量。
示例:
1 2 3 4 5 6 7 8 |
function modifyValue(x) { x = 10; console.log("Inside function:", x); // 输出 10 } let num = 5; modifyValue(num); console.log("Outside function:", num); // 输出 5(未被修改) |
- 解释:在这个例子中,
num
是一个基本类型(number
),传递给函数modifyValue
后,在函数内部对x
的修改不会影响外部的num
,因为num
的值是按值传递的(即x
是num
的一个副本)。
2. 按引用传递(Pass by Reference)
对于复杂数据类型(如object
、array
、function
),JavaScript 是按引用传递的。传递的不是对象的副本,而是对象的引用,因此在函数内部修改对象的属性会影响原始对象。
示例:
1 2 3 4 5 6 7 8 |
function modifyObject(obj) { obj.name = "Alice"; console.log("Inside function:", obj); // 输出 { name: "Alice" } } let person = { name: "Bob" }; modifyObject(person); console.log("Outside function:", person); // 输出 { name: "Alice" }(被修改) |
- 解释:在这个例子中,
person
是一个对象类型,传递给modifyObject
函数时,传递的是对象的引用,因此在函数内部修改对象属性会影响到原始对象。
3. 按引用传递但不改变引用本身
虽然对象是按引用传递的,但如果你试图在函数内改变引用本身(即将它指向一个新对象),那么这种改变不会影响外部的对象引用。
示例:
1 2 3 4 5 6 7 8 |
function replaceObject(obj) { obj = { name: "Charlie" }; // 尝试用新对象替换原对象 console.log("Inside function:", obj); // 输出 { name: "Charlie" } } let person = { name: "Bob" }; replaceObject(person); console.log("Outside function:", person); // 输出 { name: "Bob" }(未被替换) |
- 解释:在这个例子中,虽然传递的是引用,但在函数内部把
obj
重新赋值为一个新对象时,改变的只是obj
本身的引用,而不会影响外部的person
。
总结
改变引用不会影响外部对象:在函数内部将引用重新赋值时,外部对象的引用不会受影响。
按值传递:基本类型的值传递,修改不会影响原始值。
按引用传递:对象类型的引用传递,修改对象的属性会影响原始对象。
HarmonyOS:ForEach
接口描述
1 2 3 4 5 |
ForEach( arr: Array, itemGenerator: (item: any, index: number) => void, keyGenerator?: (item: any, index: number) => string ) |
示例
首次渲染
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
@Entry @Component struct Parent { @State simpleList: Array<string> = ['one', 'two', 'three']; build() { Row() { Column() { ForEach(this.simpleList, (item: string) => { ChildItem({ item: item }) }, (item: string) => item) } .width('100%') .height('100%') } .height('100%') .backgroundColor(0xF1F3F5) } } @Component struct ChildItem { @Prop item: string; build() { Text(this.item) .fontSize(50) } } |
数据源存在相同值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
@Entry @Component struct Parent { @State simpleList: Array<string> = ['one', 'two', 'two', 'three']; build() { Row() { Column() { ForEach(this.simpleList, (item: string) => { ChildItem({ item: item }) }, (item: string) => item) } .width('100%') .height('100%') } .height('100%') .backgroundColor(0xF1F3F5) } } @Component struct ChildItem { @Prop item: string; build() { Text(this.item) .fontSize(50) } } |
非首次渲染
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
@Entry @Component struct Parent { @State simpleList: Array<string> = ['one', 'two', 'three']; build() { Row() { Column() { Text('点击修改第3个数组项的值') .fontSize(24) .fontColor(Color.Red) .onClick(() => { this.simpleList[2] = 'new three'; }) ForEach(this.simpleList, (item: string) => { ChildItem({ item: item }) .margin({ top: 20 }) }, (item: string) => item) } .justifyContent(FlexAlign.Center) .width('100%') .height('100%') } .height('100%') .backgroundColor(0xF1F3F5) } } @Component struct ChildItem { @Prop item: string; build() { Text(this.item) .fontSize(30) } } |
骨架屏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
@Entry @Component struct ArticleList { @State simpleList: Array<number> = [1, 2, 3, 4, 5]; build() { Column() { ForEach(this.simpleList, (item: number) => { ArticleSkeletonView() .margin({ top: 20 }) }, (item: number) => item.toString()) } .padding(20) .width('100%') .height('100%') } } @Builder function textArea(width: number | Resource | string = '100%', height: number | Resource | string = '100%') { Row() .width(width) .height(height) .backgroundColor('#FFF2F3F4') } @Component struct ArticleSkeletonView { build() { Row() { Column() { textArea(80, 80) } .margin({ right: 20 }) Column() { textArea('60%', 20) textArea('50%', 20) } .alignItems(HorizontalAlign.Start) .justifyContent(FlexAlign.SpaceAround) .height('100%') } .padding(20) .borderRadius(12) .backgroundColor('#FFECECEC') .height(120) .width('100%') .justifyContent(FlexAlign.SpaceBetween) } } |
数据源数组项变化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
class Article { id: string; title: string; brief: string; constructor(id: string, title: string, brief: string) { this.id = id; this.title = title; this.brief = brief; } } @Entry @Component struct ArticleListView { @State isListReachEnd: boolean = false; @State articleList: Array<Article> = [ new Article('001', '第1篇文章', '文章简介内容'), new Article('002', '第2篇文章', '文章简介内容'), new Article('003', '第3篇文章', '文章简介内容'), new Article('004', '第4篇文章', '文章简介内容'), new Article('005', '第5篇文章', '文章简介内容'), new Article('006', '第6篇文章', '文章简介内容') ] loadMoreArticles() { this.articleList.push(new Article('007', '加载的新文章', '文章简介内容')); } build() { Column({ space: 5 }) { List() { ForEach(this.articleList, (item: Article) => { ListItem() { ArticleCard({ article: item }) .margin({ top: 20 }) } }, (item: Article) => item.id) } .onReachEnd(() => { this.isListReachEnd = true; }) .parallelGesture( PanGesture({ direction: PanDirection.Up, distance: 80 }) .onActionStart(() => { if (this.isListReachEnd) { this.loadMoreArticles(); this.isListReachEnd = false; } }) ) .padding(20) .scrollBar(BarState.Off) } .width('100%') .height('100%') .backgroundColor(0xF1F3F5) } } @Component struct ArticleCard { @Prop article: Article; build() { Row() { Image($r('app.media.icon')) .width(80) .height(80) .margin({ right: 20 }) Column() { Text(this.article.title) .fontSize(20) .margin({ bottom: 8 }) Text(this.article.brief) .fontSize(16) .fontColor(Color.Gray) .margin({ bottom: 8 }) } .alignItems(HorizontalAlign.Start) .width('80%') .height('100%') } .padding(20) .borderRadius(12) .backgroundColor('#FFECECEC') .height(120) .width('100%') .justifyContent(FlexAlign.SpaceBetween) } } |
数据源数组项子属性变化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
@Observed class Article { id: string; title: string; brief: string; isLiked: boolean; likesCount: number; constructor(id: string, title: string, brief: string, isLiked: boolean, likesCount: number) { this.id = id; this.title = title; this.brief = brief; this.isLiked = isLiked; this.likesCount = likesCount; } } @Entry @Component struct ArticleListView { @State articleList: Array<Article> = [ new Article('001', '第0篇文章', '文章简介内容', false, 100), new Article('002', '第1篇文章', '文章简介内容', false, 100), new Article('003', '第2篇文章', '文章简介内容', false, 100), new Article('004', '第4篇文章', '文章简介内容', false, 100), new Article('005', '第5篇文章', '文章简介内容', false, 100), new Article('006', '第6篇文章', '文章简介内容', false, 100), ]; build() { List() { ForEach(this.articleList, (item: Article) => { ListItem() { ArticleCard({ article: item }) .margin({ top: 20 }) } }, (item: Article) => item.id) } .padding(20) .scrollBar(BarState.Off) .backgroundColor(0xF1F3F5) } } @Component struct ArticleCard { @ObjectLink article: Article; handleLiked() { this.article.isLiked = !this.article.isLiked; this.article.likesCount = this.article.isLiked ? this.article.likesCount + 1 : this.article.likesCount - 1; } build() { Row() { Image($r('app.media.icon')) .width(80) .height(80) .margin({ right: 20 }) Column() { Text(this.article.title) .fontSize(20) .margin({ bottom: 8 }) Text(this.article.brief) .fontSize(16) .fontColor(Color.Gray) .margin({ bottom: 8 }) Row() { Image(this.article.isLiked ? $r('app.media.iconLiked') : $r('app.media.iconUnLiked')) .width(24) .height(24) .margin({ right: 8 }) Text(this.article.likesCount.toString()) .fontSize(16) } .onClick(() => this.handleLiked()) .justifyContent(FlexAlign.Center) } .alignItems(HorizontalAlign.Start) .width('80%') .height('100%') } .padding(20) .borderRadius(12) .backgroundColor('#FFECECEC') .height(120) .width('100%') .justifyContent(FlexAlign.SpaceBetween) } } |
拖拽排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
@Entry @Component struct ForEachSort { @State arr: Array<string> = []; build() { Row() { List() { ForEach(this.arr, (item: string) => { ListItem() { Text(item.toString()) .fontSize(16) .textAlign(TextAlign.Center) .size({height: 100, width: "100%"}) }.margin(10) .borderRadius(10) .backgroundColor("#FFFFFFFF") }, (item: string) => item) .onMove((from:number, to:number) => { let tmp = this.arr.splice(from, 1); this.arr.splice(to, 0, tmp[0]) }) } .width('100%') .height('100%') .backgroundColor("#FFDCDCDC") } } aboutToAppear(): void { for (let i = 0; i < 100; i++) { this.arr.push(i.toString()) } } } |
文档地址
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-rendering-control-foreach-V5
HarmonyOS中级第一课01:HAR
HarmonyOS中级第一课01:HSP
HarmonyOS中级第一课01:UIAbility组件间的交互
HarmonyOS获取bundleName
HarmonyOS中级第一课01:AbilityStage组件容器介绍
第一章 常用半导体器件
1、半导体基础知识
一、本征半导体
二、杂质半导体
三、PN结的形成及其单向导电性
四、PN结的电容效应
一、本征半导体
1、什么是半导体?什么是本征半导体?
导电性介于导体与绝缘体之间的物质称为半导体。
导体——铁、铝、铜等金属元素等价低元素,其最外层电子在外电场作用下很容易产生定向移动,形成电流。
绝缘体——惰性气体、橡胶等,其原子的最外层电子受原子核的束缚力很强,只有在外电场强到一定程度时才可能导电。
半导体——硅(Si)、锗(Ge),均为四价元素,它们原子的最外层电子受原子核的束缚力介于导体与绝缘体之间。
本征半导体是纯净的晶体结构的半导体。
2、本征半导体的结构
自由电子与空穴相碰同时消失,称为复合。
一定温度下,自由电子与空穴对的浓度一定;温度升高,热运动加剧,挣脱共价键的电子增多,自由电子与空穴对的浓度加大。
3、本征半导体中的两种载流子
运载电荷的粒子称为载流子。
外加电场时,带负电的自由电子和带正电的空穴均参与导电,且运动方向相反。由于载流子数目很少,故导电性很差。
温度升高,热运动加剧,载流子浓度增大,导电性增强。
热力学温度0K时不导电。
为什么要将半导体变成导电性很差的本征半导体?
二、杂质半导体
1.N型半导体
杂志半导体主要靠多数载流子导电。掺入杂质越多,电子浓度越高,导电性越强,实现导电性可控。
2.P型半导体
P型半导体主要靠空穴导电,掺入杂质越多,空穴浓度越高,导电性越强。
在杂质半导体中,温度变化时,载流子的数目变化吗?少子与多子变化的数目相同吗?少子与多子浓度的变化相同吗?
1.变化
2.相同
3.不同:加入多数载流子增加了两个,少数载流子也增加了两个,可能多数载流子增加了千分之一,而少数载流子只增加了百分之一。
三、PN结的形成及其单向导电性
物质因浓度差而产生的运动称为扩散运动。气体、液体、固体均有之。
PN结的形成
由于扩散运动使P区与N区的交界面缺少多数载流子,形成内电场,从而阻止扩散运动的进行。内电场使空穴从N区向P区、自由电子从P区向N区运动。
参与扩散运动和漂移运动的载流子数目相同,达到动态平衡,就形成了PN结。
PN结的单向导电性
PN结加正向电压导通:
耗尽层变窄,扩散运动加剧,由于外电源的作用,形成扩散电流,PN结处于导通状态。
PN结加反向电压截至:
耗尽层变宽,阻止扩散运动,有利于漂移运动,形成漂移电流。由于电流很小,故可近似认为其截至。