活动网站推广方案,电子书制作公司网站,杭州网站建设推荐,wordpress页面镶入文章目录
1 - 绘制图形
1.1 - 绘制基本几何图形
1.2 - 绘制自定义几何图形
2 - 添加动画效果
2.1 - animateTo实现闪屏动画
2.2 - 页面转场动画
3 - 常见组件说明 1 - 绘制图形
绘制能力主要是通过框架提供的绘制组件来支撑#xff0c;支…目录
1 - 绘制图形
1.1 - 绘制基本几何图形
1.2 - 绘制自定义几何图形
2 - 添加动画效果
2.1 - animateTo实现闪屏动画
2.2 - 页面转场动画
3 - 常见组件说明 1 - 绘制图形
绘制能力主要是通过框架提供的绘制组件来支撑支持svg标准绘制命令。
1.1 - 绘制基本几何图形
绘制组件封装了一些常见的基本几何图形比如矩形Rect、圆形Circle、椭圆形Ellipse等为开发者省去了路线计算的过程。
FoodDetail页面的食物成分表里给每一项成分名称前都加上一个圆形的图标作为成分标签。
1. 创建Circle组件在每一项含量成分前增加一个圆形图标作为标签。设置Circle的直径为 6vp。修改FoodDetail页面的ContentTable组件里的IngredientItem方法在成分名称前添加Circle。
// FoodDetail.ets
Component
struct ContentTable {private foodItem: FoodDataBuilder IngredientItem(title:string, colorValue: string, name: string, value: string) {Flex() {Text(title).fontSize(17.4).fontWeight(FontWeight.Bold).layoutWeight(1)Flex({ alignItems: ItemAlign.Center }) {Circle({width: 6, height: 6}).margin({right: 12}).fill(colorValue)Text(name).fontSize(17.4).flexGrow(1)Text(value).fontSize(17.4)}.layoutWeight(2)}}build() {......}
}
2. 每个成分的标签颜色不一样所以我们在build方法中调用IngredientItem给每个Circle填充不一样的颜色。
// FoodDetail.ets
Component
struct ContentTable {private foodItem: FoodDataBuilder IngredientItem(title:string, colorValue: string, name: string, value: string) {Flex() {Text(title).fontSize(17.4).fontWeight(FontWeight.Bold).layoutWeight(1)Flex({ alignItems: ItemAlign.Center }) {Circle({width: 6, height: 6}).margin({right: 12}).fill(colorValue)Text(name).fontSize(17.4).flexGrow(1)Text(value).fontSize(17.4)}.layoutWeight(2)}}build() {Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Start }) {this.IngredientItem(Calories, #FFf54040, Calories, this.foodItem.calories kcal)this.IngredientItem(Nutrition, #FFcccccc, Protein, this.foodItem.protein g)this.IngredientItem( , #FFf5d640, Fat, this.foodItem.fat g)this.IngredientItem( , #FF9e9eff, Carbohydrates, this.foodItem.carbohydrates g)this.IngredientItem( , #FF53f540, VitaminC, this.foodItem.vitaminC mg)}.height(280).padding({ top: 30, right: 30, left: 30 })}
} 1.2 - 绘制自定义几何图形
除绘制基础几何图形开发者还可以使用Path组件来绘制自定义的路线下面进行绘制应用的Logo图案。
1. 在pages文件夹下创建新的页面Logo.ets。 2. Logo.ets中删掉模板代码创建Logo Component。
Entry
Component
struct Logo {build() {}
}
3. 创建Flex组件为根节点宽高设置为100%设置其在主轴方向和交叉轴方向的对齐方式都为Center创建Shape组件为Flex子组件。
Shape组件是所有绘制组件的父组件。如果需要组合多个绘制组件成为一个整体需要创建Shape作为其父组件。
我们要绘制的Logo的大小630px * 630px。声明式UI范式支持多种长度单位的设置在前面的章节中我们直接使用number作为参数即采用了默认长度单位vp虚拟像素单位。vp和设备分辨率以及屏幕密度有关。比如设备分辨率为1176 * 2400屏幕基准密度(resolution)为3vp px / resolution则该设备屏幕宽度是392vp。
但是绘制组件采用svg标准默认采取px为单位的为方便统一在这绘制Logo这一部分统一采取px为单位。声明式UI框架同样也支持px单位入参类型为string设置宽度为630px即210vp设置方式为width(630px)或者width(210)。
Entry
Component
struct Logo {build() {Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {Shape() {}.height(630px).width(630px)}.width(100%).height(100%)}
}
4. 给页面填充渐变色。设置为线性渐变偏移角度为180deg三段渐变 #BDE895 --95DE7F -- #7AB967其区间分别为[0, 0.1], (0.1, 0.6], (0.6, 1]。
.linearGradient({angle: 180,colors: [[#BDE895, 0.1], [#95DE7F, 0.6], [#7AB967, 1]]
}) Entry
Component
struct Logo {build() {Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {Shape() {}.height(630px).width(630px)}.width(100%).height(100%).linearGradient({angle: 180,colors: [[#BDE895, 0.1], [#95DE7F, 0.6], [#7AB967, 1]]})}
} 5. 绘制第一条路线Path设置其绘制命令。
Path().commands(M162 128.7 a222 222 0 0 1 100.8 374.4 H198 a36 36 0 0 3 -36 -36)
Path的绘制命令采用svg标准上述命令可分解为 M162 128.7 将笔触移动到(Moveto)坐标点(162, 128.7)。 a222 222 0 0 1 100.8 374.4 画圆弧线(elliptical arc)半径rxry为222x轴旋转角度x-axis-rotation为0角度大小large-arc-flag为0即小弧度角弧线方向(sweep-flag)为1即逆时针画弧线小写a为相对位置即终点坐标为(162 100.8 262.8, 128.7 374.4 503.1)。 H198 画水平线(horizontal lineto)到198即画(262.8, 503.1)到(198, 503.1)的水平线。 a36 36 0 0 3 -36 -36 画圆弧线(elliptical arc)含义同上结束点为(198 - 36 162, 503.1 - 36 467.1)。 V128.7 画垂直线(vertical lineto)到128.7即画(162, 467.1)到(162, 128.7)的垂直线。 z 关闭路径(closepath)。 填充颜色为白色。
.fill(Color.White)
Entry
Component
struct Logo {build() {Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {Shape() {Path().commands(M162 128.7 a222 222 0 0 1 100.8 374.4 H198 a36 36 0 0 3 -36 -36).fill(Color.White)}.height(630px).width(630px)}.width(100%).height(100%).linearGradient({angle: 180,colors: [[#BDE895, 0.1], [#95DE7F, 0.6], [#7AB967, 1]]})}
} 6. 在Shape组件内绘制第二个Path。第二条Path的背景色为渐变色但是渐变色的填充是其整体的box所以需要clip将其裁剪入参为Shape即按照Shape的形状进行裁剪。
Path().commands(M319.5 128.1 c103.5 0 187.5 84 187.5 187.5 v15 a172.5 172.5 0 0 3 -172.5 172.5 H198 a36 36 0 0 3 -13.8 -1 207 207 0 0 0 87 -372 h48.3 z).fill(none).linearGradient({angle: 30,colors: [[#C4FFA0, 0], [#ffffff, 1]]}).clip(new Path().commands(M319.5 128.1 c103.5 0 187.5 84 187.5 187.5 v15 a172.5 172.5 0 0 3 -172.5 172.5 H198 a36 36 0 0 3 -13.8 -1 207 207 0 0 0 87 -372 h48.3 z))
Path的绘制命令比较长可以将其作为组件的成员变量通过this调用。
Entry
Component
struct Logo {private pathCommands1:string M319.5 128.1 c103.5 0 187.5 84 187.5 187.5 v15 a172.5 172.5 0 0 3 -172.5 172.5 H198 a36 36 0 0 3 -13.8 -1 207 207 0 0 0 87 -372 h48.3 zbuild() {......Path().commands(this.pathCommands1).fill(none).linearGradient({angle: 30,colors: [[#C4FFA0, 0], [#ffffff, 1]]}).clip(new Path().commands(this.pathCommands1))......}
} 7. 在Shape组件内绘制第二个Path。
Entry
Component
struct Logo {private pathCommands1:string M319.5 128.1 c103.5 0 187.5 84 187.5 187.5 v15 a172.5 172.5 0 0 3 -172.5 172.5 H198 a36 36 0 0 3 -13.8 -1 207 207 0 0 0 87 -372 h48.3 zprivate pathCommands2:string M270.6 128.1 h48.6 c51.6 0 98.4 21 132.3 54.6 a411 411 0 0 3 -45.6 123 c-25.2 45.6 -56.4 84 -87.6 110.4 a206.1 206.1 0 0 0 -47.7 -288 zbuild() {Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {Shape() {Path().commands(M162 128.7 a222 222 0 0 1 100.8 374.4 H198 a36 36 0 0 3 -36 -36).fill(Color.White)Path().commands(this.pathCommands1).fill(none).linearGradient({angle: 30,colors: [[#C4FFA0, 0], [#ffffff, 1]]}).clip(new Path().commands(this.pathCommands1))Path().commands(this.pathCommands2).fill(none).linearGradient({angle: 50,colors: [[#8CC36A, 0.1], [#B3EB90, 0.4], [#ffffff, 0.7]]}).clip(new Path().commands(this.pathCommands2))}.height(630px).width(630px)}.width(100%).height(100%).linearGradient({angle: 180,colors: [[#BDE895, 0.1], [#95DE7F, 0.6], [#7AB967, 1]]})}
} 完成应用Logo的绘制。Shape组合了三个Path组件通过svg命令绘制出一个艺术的叶子寓意绿色健康饮食方式。
8. 添加应用的标题和slogan。
Entry
Component
struct Logo {private pathCommands1:string M319.5 128.1 c103.5 0 187.5 84 187.5 187.5 v15 a172.5 172.5 0 0 3 -172.5 172.5 H198 a36 36 0 0 3 -13.8 -1 207 207 0 0 0 87 -372 h48.3 zprivate pathCommands2:string M270.6 128.1 h48.6 c51.6 0 98.4 21 132.3 54.6 a411 411 0 0 3 -45.6 123 c-25.2 45.6 -56.4 84 -87.6 110.4 a206.1 206.1 0 0 0 -47.7 -288 zbuild() {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {Shape() {Path().commands(M162 128.7 a222 222 0 0 1 100.8 374.4 H198 a36 36 0 0 3 -36 -36).fill(Color.White)Path().commands(this.pathCommands1).fill(none).linearGradient({angle: 30,colors: [[#C4FFA0, 0], [#ffffff, 1]]}).clip(new Path().commands(this.pathCommands1))Path().commands(this.pathCommands2).fill(none).linearGradient({angle: 50,colors: [[#8CC36A, 0.1], [#B3EB90, 0.4], [#ffffff, 0.7]]}).clip(new Path().commands(this.pathCommands2))}.height(630px).width(630px)Text(Healthy Diet).fontSize(26).fontColor(Color.White).margin({ top:300 })Text(Healthy life comes from a balanced diet).fontSize(17).fontColor(Color.White).margin({ top:4 })}.width(100%).height(100%).linearGradient({angle: 180,colors: [[#BDE895, 0.1], [#95DE7F, 0.6], [#7AB967, 1]]})}
} 2 - 添加动画效果
2.1 - animateTo实现闪屏动画
声明式UI范式组件动画包括属性动画和animateTo显式动画
属性动画设置组件通用属性变化的动画效果。显式动画可以设置组件从状态A到状态B的变化动画效果包括样式、位置信息和节点的增加删除等开发者无需关注变化过程只需指定起点和终点的状态。animateTo还提供播放状态的回调接口是对属性动画的增强与封装。
闪屏页面的动画效果是Logo图标的渐出和放大效果的动画动画结束后跳转到食物分类列表页面。接下来我们就使用animateTo来实现启动页动画的闪屏效果。
1. 动画效果自动播放。闪屏动画的预期效果是进入Logo页面后animateTo动画效果自动开始播放可以借助于组件显隐事件的回调接口来实现。调用Shape的onAppear方法设置其显式动画。
Shape() {...
}
.onAppear(() {animateTo()
})
2. 创建opacity和scale数值的成员变量用装饰器State修饰。表示其为有状态的数据即改变会触发页面的刷新。
Entry
Component
struct Logo {State private opacityValue: number 0State private scaleValue: number 0build() {Shape() {...}.scale({ x: this.scaleValue, y: this.scaleValue }).opacity(this.opacityValue).onAppear(() {animateTo()})}
}
3. 设置animateTo的动画曲线curve。Logo的加速曲线为先慢后快使用贝塞尔曲线cubicBeziercubicBezier(0.4, 0, 1, 1)。
需要使用动画能力接口中的插值计算首先要导入curves模块。
import Curves from ohos.curves
ohos.curves模块提供了线性Curve. Linear、阶梯step、三阶贝塞尔(cubicBezier)和弹簧(spring)插值曲线的初始化函数可以根据入参创建一个插值曲线对象。
Entry
Component
struct Logo {State private opacityValue: number 0State private scaleValue: number 0private curve1 Curves.cubicBezier(0.4, 0, 1, 1)build() {Shape() {...}.scale({ x: this.scaleValue, y: this.scaleValue }).opacity(this.opacityValue).onAppear(() {animateTo({curve: this.curve1})})}
}
4. 设置动画时长为1s延时0.1s开始播放设置显示动效event的闭包函数即起点状态到终点状态为透明度opacityValue和大小scaleValue从0到1实现Logo的渐出和放大效果。
Entry
Component
struct Logo {State private opacityValue: number 0State private scaleValue: number 0private curve1 Curves.cubicBezier(0.4, 0, 1, 1)build() {Shape() {...}.scale({ x: this.scaleValue, y: this.scaleValue }).opacity(this.opacityValue).onAppear(() {animateTo({duration: 1000, curve: this.curve1, delay: 100, }, () {this.opacityValue 1this.scaleValue 1})})}
}
5. 闪屏动画播放结束后定格1s进入FoodCategoryList页面。设置animateTo的onFinish回调接口调用定时器Timer的setTimeout接口延时1s后调用router.replace显示FoodCategoryList页面。
import router from ohos.routerEntry
Component
struct Logo {State private opacityValue: number 0State private scaleValue: number 0private curve1 Curves.cubicBezier(0.4, 0, 1, 1)build() {Shape() {...}.scale({ x: this.scaleValue, y: this.scaleValue }).opacity(this.opacityValue).onAppear(() {animateTo({duration: 1000,curve: this.curve1, delay: 100, onFinish: () {setTimeout(() {router.replace({ url: pages/FoodCategoryList })}, 1000);}}, () {this.opacityValue 1this.scaleValue 1})})}
}
整体代码如下。
import Curves from ohos.curves
import router from ohos.routerEntry
Component
struct Logo {State private opacityValue: number 0State private scaleValue: number 0private curve1 Curves.cubicBezier(0.4, 0, 1, 1)private pathCommands1: string M319.5 128.1 c103.5 0 187.5 84 187.5 187.5 v15 a172.5 172.5 0 0 3 -172.5 172.5 H198 a36 36 0 0 3 -13.8 -1 207 207 0 0 0 87 -372 h48.3 zprivate pathCommands2: string M270.6 128.1 h48.6 c51.6 0 98.4 21 132.3 54.6 a411 411 0 0 3 -45.6 123 c-25.2 45.6 -56.4 84 -87.6 110.4 a206.1 206.1 0 0 0 -47.7 -288 zbuild() {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {Shape() {Path().commands(M162 128.7 a222 222 0 0 1 100.8 374.4 H198 a36 36 0 0 3 -36 -36).fill(Color.White)Path().commands(this.pathCommands1).fill(none).linearGradient({angle: 30,colors: [[#C4FFA0, 0], [#ffffff, 1]]}).clip(new Path().commands(this.pathCommands1))Path().commands(this.pathCommands2).fill(none).linearGradient({angle: 50,colors: [[#8CC36A, 0.1], [#B3EB90, 0.4], [#ffffff, 0.7]]}).clip(new Path().commands(this.pathCommands2))}.height(630px).width(630px).scale({ x: this.scaleValue, y: this.scaleValue }).opacity(this.opacityValue).onAppear(() {animateTo({duration: 1000,curve: this.curve1,delay: 100,onFinish: () {setTimeout(() {router.replace({ url: pages/FoodCategoryList })}, 1000);}}, () {this.opacityValue 1this.scaleValue 1})})Text(Healthy Diet).fontSize(26).fontColor(Color.White).margin({ top: 300 })Text(Healthy life comes from a balanced diet).fontSize(17).fontColor(Color.White).margin({ top: 4 })}.width(100%).height(100%).linearGradient({angle: 180,colors: [[#BDE895, 0.1], [#95DE7F, 0.6], [#7AB967, 1]]})}
}
2.2 - 页面转场动画
食物分类列表页和食物详情页之间的共享元素转场即点击FoodListItem/FoodGridItem后食物缩略图会放大随着页面跳转到食物详情页的大图。
1. 设置FoodListItem和FoodGridItem的Image组件的共享元素转场方法(sharedTransition)。转场id为foodItem.id转场动画时长为1s延时0.1s播放变化曲线为贝塞尔曲线Curves.cubicBezier(0.2, 0.2, 0.1, 1.0) 需引入curves模块。
共享转场时会携带当前元素的被设置的属性所以创建Row组件使其作为Image的父组件设置背景颜色在Row上。
在FoodListItem的Image组件上设置autoResize为false因为image组件默认会根据最终展示的区域去调整图源的大小以优化图片渲染性能。在转场动画中图片在放大的过程中会被重新加载所以为了转场动画的流畅autoResize设置为false。
// FoodList.ets
import Curves from ohos.curvesComponent
struct FoodListItem {private foodItem: FoodDatabuild() {Navigator({ target: pages/FoodDetail }) {Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {Row() {Image(this.foodItem.image).objectFit(ImageFit.Contain).autoResize(false).height(40).width(40).sharedTransition(this.foodItem.id, { duration: 1000, curve: Curves.cubicBezier(0.2, 0.2, 0.1, 1.0), delay: 100 })}.margin({ right: 16 })Text(this.foodItem.name).fontSize(14).flexGrow(1)Text(this.foodItem.calories kcal).fontSize(14)}.height(64)}.params({ foodData: this.foodItem }).margin({ right: 24, left:32 })}
}Component
struct FoodGridItem {private foodItem: FoodDatabuild() {Column() {Row() {Image(this.foodItem.image).objectFit(ImageFit.Contain).autoResize(false).height(152).width(100%).sharedTransition(this.foodItem.id, { duration: 1000, curve: Curves.cubicBezier(0.2, 0.2, 0.1, 1.0), delay: 100 })}Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {Text(this.foodItem.name).fontSize(14).flexGrow(1).padding({ left: 8 })Text(this.foodItem.calories kcal).fontSize(14).margin({ right: 6 })}.height(32).width(100%).backgroundColor(#FFe5e5e5)}.height(184).width(100%).onClick(() {router.push({ url: pages/FoodDetail, params: { foodId: this.foodItem } })})}
}
2. 设置FoodDetail页面的FoodImageDisplay的Image组件的共享元素转场方法(sharedTransition)。设置方法同上。
import Curves from ohos.curvesComponent
struct FoodImageDisplay {private foodItem: FoodDatabuild() {Stack({ alignContent: Alignment.BottomStart }) {Image(this.foodItem.image).objectFit(ImageFit.Contain).sharedTransition(this.foodItem.id, { duration: 1000, curve: Curves.cubicBezier(0.2, 0.2, 0.1, 1.0), delay: 100 })Text(this.foodItem.name).fontSize(26).fontWeight(500).margin({ left: 26, bottom: 17.4 })}.height(357) }
}
3 - 常见组件说明
组件是构建页面的核心每个组件通过对数据和方法的简单封装实现独立的可视、可交互功能单元。组件之间相互独立随取随用也可以在需求相同的地方重复使用。
声明式开发范式目前可供选择的组件如下表所示。
组件类型基础组件Blank、Button、Checkbox、CheckboxGroup、DataPanel、DatePicker、Divider、Gauge、Image、ImageAnimator、LoadingProgress、Marquee、Navigation、Progress、QRCode、Radio、Rating、RichText、ScrollBar、Search、Select、Slider、Span、Stepper、StepperItem、Text、TextArea、TextClock、TextInput、TextPicker、TextTimer、TimePicker、Toggle、Web、XComponent容器组件AlphabetIndexer、Badge、Column、ColumnSplit、Counter、Flex、GridContainer、Grid、GridItem、List、ListItem、Navigator、Panel、Refresh、Row、RowSplit、Scroll、SideBarContainer、Stack、Swiper、Tabs、TabContent媒体组件Video绘制组件Circle、Ellipse、Line、Polyline、Polygon、Path、Rect、Shape画布组件Canvas 感谢各位大佬支持
互三啦