π HarmonyOS News Home Page Development Guide: Smooth Animation + Lazy Loading Practice
Hey HarmonyOS Developers! Today I'm sharing a super practical solution for developing a news-style homepage in HarmonyOS. I've dug out a treasure case from the official docs! From smooth tab switching animations to silky lazy loading lists, I'll walk you through building a high-performance news homepageπ
π Overall Scene Effect
User Operation Flow:
- Get location permission β 2. Tap the top address bar to switch city β 3. Swipe/click Tab to switch news category β 4. Pull down to refresh + pull up to load more β 5. One-click back to top (Actual effect is smoother than GIF)
Performance Highlights:
- Tab switch response delay only 51ms
- Pull-down refresh response 153ms, pull-up load 150ms
- Bottom navigation Lottie animation frame rate stable at 60FPS
π₯ Core Module Code Practice
1οΈβ£ Navigation Bar Switch Animation (51ms Response Secret)
Problem: Using<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(252, 252, 252);">onChange</font>
event causes animation delay!
Correct Solution: Use<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(252, 252, 252);">onAnimationStart</font>
to trigger animation synchronously
// TabBar.ets
build() {
Tabs({ barPosition: BarPosition.Start }) {
ForEach(this.tabBarArray, (item) => {
TabContent() { /* News List */ }
})
}
.onAnimationStart((_, targetIndex) => {
this.currentIndex = targetIndex; // Key! Sync tab state in real time
playTabAnimation(); // Custom animation function
})
}
π‘ Pitfall Guide:
- Avoid using
<font style="color:rgba(0, 0, 0, 0.4);background-color:rgb(252, 252, 252);">onClick</font>
(conflicts with swipe) - Animation resources should be less than 30KB (ensure loading speed)
2οΈβ£ Bottom Navigation Lottie Animation (349ms Ultimate Experience)
Three Steps to Achieve Dynamic Icons:
Step 1: Install animation library
ohpm install @ohos/lottie
Step 2: Encapsulate animation controller
// Home.ets
import lottie from '@ohos/lottie';
private lottieController() {
lottie.stop(); // Stop previous animation
lottie.play(this.tabOptions[this.currentIndex].name); // Play current tab animation
}
Step 3: Render animation in Canvas
Canvas(this.canvasContext)
.onReady(() => {
lottie.loadAnimation({
container: this.canvasContext,
path: 'common/lottie_home.json', // Animation resource path
autoplay: false
});
})
π Tips:
- Use
<font style="color:rgba(0, 0, 0, 0.4);background-color:rgb(252, 252, 252);">RenderingContextSettings(true)</font>
to enable anti-aliasing - Put animation JSON files in
<font style="color:rgba(0, 0, 0, 0.4);background-color:rgb(252, 252, 252);">entry/src/main/resources/rawfile</font>
directory
3οΈβ£ Pull Down to Refresh & Pull Up to Load (150ms Response)
Awesome Third-Party Library:<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(252, 252, 252);">pullToRefresh</font>
// Install dependency
ohpm install @ohos/pulltorefresh
// Usage example
PullToRefresh({
data: $newsData, // Data source
scroller: this.scroller, // Scroll controller
onRefresh: () => {
return new Promise((resolve) => {
fetchNewData(); // Simulate network request
setTimeout(resolve, 500);
});
},
onLoadMore: () => { /* Similar implementation */ }
}) {
LazyForEach(this.newsData, (item) => {
NewsItem({ data: item }) // Encapsulated news item component
})
}
β οΈ Key Configuration:
<font style="color:rgba(0, 0, 0, 0.4);background-color:rgb(252, 252, 252);">List</font>
component must set <font style="color:rgba(0, 0, 0, 0.4);background-color:rgb(252, 252, 252);">edgeEffect: EdgeEffect.None</font>
to avoid native scroll conflict
4οΈβ£ Homepage Feed Lazy Loading (Smooth with Tens of Thousands of Data)
Performance Core:<font style="color:rgba(0, 0, 0, 0.9);background-color:rgb(252, 252, 252);">LazyForEach</font>
+ Pagination Loading
List() {
LazyForEach(this.newsDataSource, (item: NewsData) => {
ListItem() {
NewsItem({
title: item.title,
image: item.image,
// ...
})
}
}, item => item.id.toString())
}
.onScrollIndex((first, last) => {
if (last > this.data.length - 5) {
loadMoreData(); // Load more when reaching the bottom
}
})
π Optimization Points:
- Use
<font style="color:rgba(0, 0, 0, 0.4);background-color:rgb(252, 252, 252);">AsyncImage</font>
for async image loading - Use
<font style="color:rgba(0, 0, 0, 0.4);background-color:rgb(252, 252, 252);">TextOptimization</font>
to enable font cache for text
5οΈβ£ Address Selection Page (Accurate Positioning + Fast Search)
Dual Approach:
- Location Service: Get real-time geographic info
- AlphabetIndexer: City index navigation
// Get current location
geoLocationManager.getCurrentLocation((err, location) => {
if (location) {
geoLocationManager.getAddressesFromLocation({
latitude: location.latitude,
longitude: location.longitude
}, (err, address) => {
AppStorage.setOrCreate('currentCity', address[0].locality);
});
}
});
// City index list
AlphabetIndexer({ arrayValue: ['A','B','C'...] })
.onSelect((index) => {
this.scroller.scrollToIndex(index); // Jump to corresponding letter
})
π Permission Configuration:
Add in<font style="color:rgba(0, 0, 0, 0.4);background-color:rgb(252, 252, 252);">module.json5</font>
:
"requestPermissions": [
"ohos.permission.LOCATION",
"ohos.permission.APPROXIMATELY_LOCATION"
]
π Summary
This news homepage solution perfectly integrates:
β
Performance Optimization: LazyForEach lazy loading + animation priority control
β
Experience Upgrade: Delicate Lottie animation + gesture interaction feedback
β
Development Efficiency: Third-party components (pullToRefresh/lottie) quick integration
One last word: I'll bring more practical cases next time! If you find it useful, remember to like and bookmarkπ β See you in the comments if you have questionsπ
Top comments (0)