Read the original article:Tabs component preloading
Problem Description
Can Tabs' subcomponents be preloaded in advance? What is the specific implementation method?
Background Knowledge
The preloadItems method of the Tabs component can control Tabs to preload specified child nodes.
The cachedCount of the Swiper component can set the number of preloaded subcomponents.
Troubleshooting Process
- Identify the Preloading Requirement
- Inspect Current Component Setup
- Evaluate Performance Constraints
- Check for Custom Implementations
- Test and Iterate Solutions
- Debug Common Issues
Solution
Solution 1: Calling the preloadItems API of the Tabs component will load all specified child nodes at once. For performance reasons, it is recommended to load child nodes in batches. For specific code examples, see Example 11 Preloading Child Nodes on the official website .
Solution 2: The Swiper component supports preloading. You can use the Swiper component to build custom tabs and implement the preloading function. Please refer to the following sample code:
@Entry
@ComponentV2
struct TabsPreLoadDemo {
@Local tabNames: string[] = ['Airplane', 'Railway', 'Self-driving', 'Subway', 'Bus', 'Bicycle']
@Local selectedTabIndex: number = 0
@Local indicatorLeftOffset: number = 0
@Local indicatorOffset: number = 0
@Local firstWidth: number = -1
@Local otherWidth: number = -1
@Local swiperController: SwiperController = new SwiperController()
@Local swiperWidth: number = 0
build() {
RelativeContainer() {
Stack() {
Rect()
.height(30)
.stroke(Color.Black)
.radius(10)
.width(this.firstWidth)
.fill('#bff9f2')
.position({
left: this.indicatorLeftOffset + this.indicatorOffset,
bottom: 0
})
.animation({ duration: 300, curve: Curve.LinearOutSlowIn })
}
.width('100%')
.alignRules({
center: { anchor: 'Tabs', align: VerticalAlign.Center }
})
Row() {
ForEach(this.tabNames, (name: string, index: number) => {
Row() {
Text(name)
.fontSize(16)
.fontWeight(this.selectedTabIndex === index ? FontWeight.Bold : FontWeight.Normal)
.textAlign(TextAlign.Center)
.animation({ duration: 300 })
Image($r('app.media.startIcon'))
.width(14)
.height(14)
.margin({ left: 2 })
.visibility(this.selectedTabIndex === index ? Visibility.Visible : Visibility.None)
.animation({ duration: 300 })
}
.justifyContent(FlexAlign.Center)
.layoutWeight(this.selectedTabIndex === index ? 1.5 : 1)
.animation({ duration: 300 })
.onClick(() => {
this.selectedTabIndex = index;
this.swiperController.changeIndex(index, false);
this.getUIContext().animateTo({ duration: 500, curve: Curve.LinearOutSlowIn }, () => {
this.indicatorLeftOffset = this.otherWidth * index;
})
})
})
}
.width('100%')
.height(30)
.id('Tabs')
.onAreaChange((oldValue: Area, newValue: Area) => {
let tabWidth = newValue.width.valueOf() as number;
this.firstWidth = 1.5 * tabWidth / (this.tabNames.length + 0.5);
this.otherWidth = tabWidth / (this.tabNames.length + 0.5);
})
Swiper(this.swiperController) {
ForEach(this.tabNames, (name: string, index: number) => {
Column() {
Text(`${name} - ${index}`)
.fontSize(24)
.fontWeight(FontWeight.Bold)
}
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.height('100%')
.width('100%')
})
}
.cachedCount(3)
.onAnimationStart((index: number, targetIndex: number, extraInfo: SwiperAnimationEvent) => {
if (targetIndex > index) {
this.indicatorLeftOffset += this.otherWidth;
} else if (targetIndex < index) {
this.indicatorLeftOffset -= this.otherWidth;
}
this.indicatorOffset = 0
this.selectedTabIndex = targetIndex
})
.onAnimationEnd((index: number, extraInfo: SwiperAnimationEvent) => {
this.indicatorOffset = 0
})
.onGestureSwipe((index: number, extraInfo: SwiperAnimationEvent) => {
let move: number = this.GetOffset(extraInfo.currentOffset);
if ((this.selectedTabIndex === 0 && extraInfo.currentOffset > 0) ||
(this.selectedTabIndex === this.tabNames.length - 1 && extraInfo.currentOffset < 0)) {
return;
}
this.indicatorOffset = extraInfo.currentOffset < 0 ? move : -move;
})
.onAreaChange((oldValue: Area, newValue: Area) => {
let width = newValue.width.valueOf() as number;
this.swiperWidth = width;
})
.curve(Curve.LinearOutSlowIn)
.loop(false)
.indicator(false)
.width('100%')
.id('MainContext')
.alignRules({
top: { anchor: 'Tabs', align: VerticalAlign.Bottom },
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
})
}
.height('100%')
.width('100%')
.padding(10)
}
GetOffset(swiperOffset: number): number {
let swiperMoveRatio: number = Math.abs(swiperOffset / this.swiperWidth);
let tabMoveValue: number = swiperMoveRatio >= 1 ? this.otherWidth : this.otherWidth * swiperMoveRatio;
return tabMoveValue;
}
}
Comparison of the two solutions:
Solution 1: preloadItems
It can be loaded in batches and is easy to use.
In common scenarios, this method is recommended.
Solution 2: Swiper
It cannot be preloaded in batches, and requires relatively complex customization.
Customize Tabs and use the Swiper component features.
Top comments (0)