Problem Description
In a HarmonyOS application, when using the animateTo method to implement property animations for two Column components, the animations are not executed synchronously.
The problematic code is as follows:
import { display } from '@kit.ArkUI';
const SCREEN_WIDTH = display.getDefaultDisplaySync().width;
@Entry
@Component
struct Index {
@State translateX: number = SCREEN_WIDTH
@State lastTranslateX: number = 0
build() {
Column() {
Button('Triggering an animation')
.onClick(() => this.startAnimation())
.margin(100)
Column() {
Text('B')
.fontSize(20)
}
.width('100%')
.height(120)
.backgroundColor('#f1f3f5')
.opacity(1)
.translate({ x: this.translateX })
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
Column() {
Text('A')
.fontSize(20)
}
.width('100%')
.height(120)
.backgroundColor('#f1f3f5')
.opacity(1)
.translate({ x: this.lastTranslateX })
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
}
}
private startAnimation() {
this.getUIContext().animateTo({
duration: 1800,
curve: Curve.EaseOut
}, () => {
this.translateX = 0
this.lastTranslateX = -SCREEN_WIDTH
})
}
}
Background Knowledge
- Translate is a general property provided by HarmonyOS for setting the translation of components.
- getDefaultDisplaySync is a method provided by the display module to obtain the current default display object. Through this object, you can access screen-related properties such as width.
- UIContext provides the animateTo interface to specify transition animations for state changes caused by closure code.
- onAreaChange is a component area change event that triggers this callback when the component's area changes. This function only responds to callbacks caused by layout changes that affect the component's size or position.
Problem Analysis
In the animateTo method, all statements are executed in sequence, not synchronously.
Analysis Conclusion
Since the statements in the animateTo method can only be executed sequentially, is it possible to use other callback functions to achieve synchronized animation effects? One approach that comes to mind is using the onAreaChange callback method to synchronize the animations.
Solution
Define the newValue state variable and use the onAreaChange callback method to obtain the real-time width of component A on the screen. Then, set the translation value based on the component's width.
The complete code is shown below:
@Entry
@Component
struct AnimationOutOfSync {
@State lastTranslateX: number = 0;
@State newValue: number = 0;
@State translateX: number = this.newValue;
build() {
Column() {
Button('Triggering an animation')
.onClick(() => this.startAnimation())
.margin(100)
Column() {
Text('B')
.fontSize(20)
}
.width('100%')
.height(120)
.backgroundColor('#f1f3f5')
.translate({ x: this.translateX })
.opacity(1)
// Use onAreaChange to obtain the width of the current component
.onAreaChange((oldValue: Area, newValue: Area) => {
this.newValue = newValue.width as number;
this.translateX = newValue.width as number;
})
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
Column() {
Text('A')
.fontSize(20)
}
.width('100%')
.height(120)
.backgroundColor('#f1f3f5')
.translate({ x: this.lastTranslateX })
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
}
}
private startAnimation() {
this.getUIContext()?.animateTo({
duration: 1800,
curve: Curve.EaseOut
}, () => {
this.translateX = 0;
this.lastTranslateX = -this.newValue;
});
}
}
Top comments (0)