Read the original article:The List sub-component displays items in sequence with animations.
The List sub-component displays items in sequence with animations.
Problem Description
Lists (List) are usually displayed all at once. So, how can we achieve the animation of sub-components within the list to be displayed in a sequential chain order?
Background Knowledge
When certain common properties of a component change, a gradient transition effect can be achieved through the animation property.
Troubleshooting Process
- Problem Analysis The goal is to implement a chained animation effect for list items, where each item appears sequentially with a delay based on its position in the list.
-
Key Points Verification
-
Delay Calculation: The
indexproperty is used to calculate the delay for eachCardItem, ensuring the animation starts at increasing intervals. -
Animation Trigger: The
.onAppear()method automatically triggers the animation when the component is rendered. -
State Management: The
@State isAppearproperty controls the visibility of the animation, transitioning from hidden to visible.
-
Delay Calculation: The
-
Potential Issues
-
Dynamic Data: If the
this.dataarray changes, the order of items may shift, disrupting the chained animation sequence. - Performance: A large number of list items with significant delays could affect performance due to the sequential rendering and animation execution.
-
Dynamic Data: If the
Analysis Conclusion
-
Chained Animation Implementation
By using the
indexproperty to set the animation delay (delay: index * 120), eachCardItemis animated in sequence, creating a chained effect. -
Core Logic
- The
.onAppear()method activates theisAppearstate, which controls the opacity and translation properties, initiating the animation. - The animation delay is directly tied to the
index, ensuring each item appears in order.
- The
-
Applicable Scenarios
- Suitable for static lists or scenarios where the data order remains unchanged.
- For dynamic data, the order must align with the animation logic to maintain the chained effect.
-
Optimization Recommendations
- Avoid excessively long delays (e.g.,
index * 1000) to prevent user frustration. - For dynamic data, reset the animation state in
.onAppear()to ensure the chained effect remains consistent.
- Avoid excessively long delays (e.g.,
Solution
1.Create a List based on the data source this.
if (this.isShow) {
List() {
ForEach(this.data, (item: number) => {
ListItem() {
CardItem({ index: item })
}
.margin(10)
}, (item: number) => item.toString())
}
}
2.Create each sub-component CardItem of the List:
@Prop index: number
@State isAppear: boolean = false
build() {
Column() {
Text(`${this.index}`).fontColor(Color.Blue).fontSize(16)
}
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
.backgroundColor(Color.Green)
.height(20)
.width('100%')
.opacity(this.isAppear ? 1 : 0)
.translate({ x: this.isAppear ? 0 : 100 })
.borderRadius(8)
}
3.The CardItem component can calculate an appropriate delay time based on its index in the list, thereby achieving a cascading animation effect where the next animation starts immediately after the previous one ends.
.animation({
duration: 500,
delay: this.index * 120,
curve: Curve.EaseOut
})
4.When the CardItem component first appears in the view (i.e., when the onAppear event is triggered), the entrance animation of the component will be initiated.
.onAppear(() => {
this.isAppear = true
})
.onDisAppear(() => {
this.isAppear = false
})
5.The complete code is as follows:
@Component
struct CardItem {
@Prop index: number
@State isAppear: boolean = false
build() {
Column() {
Text(`${this.index}`).fontColor(Color.Blue).fontSize(16)
}
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
.backgroundColor(Color.Green)
.height(20)
.width('100%')
.opacity(this.isAppear ? 1 : 0)
.translate({ x: this.isAppear ? 0 : 100 })
.borderRadius(8)
.animation({
duration: 500,
delay: this.index * 120,
curve: Curve.EaseOut
})
.onAppear(() => {
this.isAppear = true
})
.onDisAppear(() => {
this.isAppear = false
})
}
}
@Entry
@Component
struct ChainList {
private data: number[] = [0, 1, 2, 3, 4, 5]
@State isShow: boolean = false
build() {
Column() {
Button('show list').onClick(() => {
this.isShow = !this.isShow
})
if (this.isShow) {
List() {
ForEach(this.data, (item: number) => {
ListItem() {
CardItem({ index: item })
}
.margin(10)
}, (item: number) => item.toString())
}
}
}.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
.width('100%')
.padding(20)
}
}

Top comments (0)