ArkUI-动画衔接

12/6/2023 ArkUI

项目案例 (opens new window)

# arkts-animation-smoothing.md

除了运行动画之外,还承载着与用户进行实时交互的功能。当用户行为根据意图变化发生改变时,UI界面应做到即时响应。例如用户在应用启动过程中,上滑退出,那么启动动画应该立即过渡到退出动画,而不应该等启动动画完成后再退出,从而减少用户等待时间

# 案例一

import curves from '@ohos.curves';
// 判断是否进行动画衔接
class SetSlt{
    public isAnimation:boolean = true
    // 类的方法
    public set():void{
        this.isAnimation = !this.isAnimation;
    }
}
@Entry
@Component
struct AnimationToAnimationDemo {
@State isHovered:boolean=false
    // 第一步:声明相关状态变量
@State SetAnimation: SetSlt = new SetSlt();

    build() {
        Column() {
            Text('ArkUI')
                // 设置文本的字体粗细
                .fontWeight(FontWeight.Bold)
                // 设置文本的字体大小
                .fontSize(12)
                // 设置文本的字体颜色
                .fontColor(Color.White)
                // 设置文本的文本对齐方式:左对齐,居中对齐,右对齐
                .textAlign(TextAlign.Center)
                // 通用样式 设置元素的外边框圆角半径
                .borderRadius(10)
                // 通用样式 设置背景颜色
                .backgroundColor(0xf56c6c)
                // 通用样式 设置组件自身的宽度
                .width(100)
                // 通用样式 设置组件自身的高度
                .height(100)
                // 第二步:将状态变量设置到相关可动画属性接口
                // 属性动画 设置页面过渡期间的缩放效果
                .scale({ x: this.SetAnimation.isAnimation ? 2 : 1, y: this.SetAnimation.isAnimation ? 2 : 1 })
                // 属性动画 设置动画曲线
                .animation({ curve: curves.springMotion(0.4, 0.8) })

            Button('Click')
                .margin({ top: 70 })
                // 点击触发
                .onClick(() => {
                    this.SetAnimation.set()
                })
            Button(this.isHovered?"Hovered":"Not Hover")
                .margin({ top: 50 })
                .onHover((isHover:boolean)=>{
                    if (isHover) {
                        this.isHovered=isHover
                    }
                })
                .onMouse((event?: MouseEvent) => {    // 设置Button的onMouse回调
                if(event){
                    console.log('Button onMouse:\n' + '' +
                        'button = ' + event.button + '\n' +
                        'action = ' + event.action + '\n' +
                        'x,y = (' + event.x + ',' + event.y + ')' + '\n' +
                        'windowXY=(' + event.x + ',' + event.y + ')');
                }
            })
        }
    .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
60
61
62
63
64
65
66
67
68
69

# 案例二

// 手势与动画的衔接
import curves from '@ohos.curves';

@Entry
@Component
struct SpringMotionDemo {
@State positionX: number = 100;
@State positionY: number = 100;
    // 直径
    diameter: number = 50;

    build() {
        Column() {
            Row() {
                // Circle 用于绘制圆形的组件
                Circle({ width: this.diameter, height: this.diameter })
                    // 设置填充区域颜色
                    .fill(Color.Blue)
                    // 组件位置坐标
                    .position({ x: this.positionX, y: this.positionY })
                    // 触摸事件 https://docs.openharmony.cn/pages/v3.2/zh-cn/application-dev/reference/arkui-ts/ts-universal-events-touch.md/
                    .onTouch((event?: TouchEvent) => {
                    if(event){
                        if (event.type === TouchType.Move) {
                            // 显式动画 https://docs.openharmony.cn/pages/v3.2/zh-cn/application-dev/reference/arkui-ts/ts-explicit-animation.md/
                            // 跟手过程,curve:动画曲线,使用responsiveSpringMotion曲线
                            animateTo({ curve: curves.responsiveSpringMotion() }, () => {
                                // 减去半径,以使球的中心运动到手指位置
                                this.positionX = event.touches[0].screenX - this.diameter / 2;
                                this.positionY = event.touches[0].screenY - this.diameter / 2;
                                console.info(`move, animateTo x:${this.positionX}, y:${this.positionY}`);
                            })
                        } else if (event.type === TouchType.Up) {
                            // 离手时,使用springMotion曲线
                            animateTo({ curve: curves.springMotion() }, () => {
                                this.positionX = 100;
                                this.positionY = 100;
                                console.info(`touchUp, animateTo x:100, y:100`);
                            })
                        }
                    }
                })
            }
        .width("100%").height("80%")
                .clip(true) // 如果球超出父组件范围,使球不可见
                .backgroundColor(Color.Orange)

            Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Start, justifyContent: FlexAlign.Center }) {
                Text("拖动小球").fontSize(16)
            }
        .width("100%")

            Row() {
                Text('点击位置: [x: ' + Math.round(this.positionX) + ', y:' + Math.round(this.positionY) + ']').fontSize(16)
            }
        .padding(10)
                .width("100%")
        }.height('100%').width('100%')
    }
}
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

# 案例三

@Entry
@Component
struct AnimateToExample {
@State widthSize: number = 250
@State heightSize: number = 100
@State rotateAngle: number = 0
    private flag: boolean = true

    build() {
        Column() {
            Button('change size')
                .width(this.widthSize)
                .height(this.heightSize)
                .margin(30)
                .onClick(() => {
                    if (this.flag) {
                        animateTo({
                            // 动画持续时间,单位为毫秒
                            duration: 2000,
                            // 动画曲线
                            curve: Curve.EaseOut,
                            // 动画播放次数。默认播放一次,设置为-1时表示无限次播放
                            iterations: 3,
                            // 动画播放模式,默认播放完成后重头开始播放
                            playMode: PlayMode.Normal,
                            // 动画播放完成回调
                            onFinish: () => {
                                console.info('play end')
                            }
                        }, () => {
                            this.widthSize = 150
                            this.heightSize = 60
                        })
                    } else {
                        animateTo({}, () => {
                            this.widthSize = 250
                            this.heightSize = 100
                        })
                    }
                    this.flag = !this.flag
                })
            // 改变旋转角度
            Button('change rotate angle')
                .margin(50)
                // https://docs.openharmony.cn/pages/v3.2/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-transformation.md/
                // 图形变换
                // 组件通用信息
                .rotate({ x: 0, y: 0, z: 1, angle: this.rotateAngle })
                .onClick(() => {
                    animateTo({
                        duration: 1200,
                        curve: Curve.Friction,
                        delay: 500,
                        iterations: -1, // 设置-1表示动画无限循环
                        playMode: PlayMode.Alternate,
                        onFinish: () => {
                            console.info('play end')
                        }
                    }, () => {
                        // 指定显示动效的闭包函数,在闭包函数中导致的状态变化系统会自动插入过渡动画
                        this.rotateAngle = 90
                    })
                })
        }.width('100%').margin({ top: 5 })
    }
}
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
Last Updated: 6/1/2024, 6:36:28 AM