告别‘Hello World’:用ArkUI实战一个仿微信‘发现’页面的鸿蒙App

张开发
2026/4/12 20:38:56 15 分钟阅读

分享文章

告别‘Hello World’:用ArkUI实战一个仿微信‘发现’页面的鸿蒙App
从零到一用ArkUI实战打造微信‘发现’页面的鸿蒙应用微信的‘发现’页面看似简单实则暗藏玄机。作为国内最流行的社交应用之一它的UI设计经过无数次迭代优化每一个像素都经过精心打磨。今天我们就以这个经典界面为蓝本用ArkUI框架一步步实现一个功能完整的仿制品。这不是简单的‘Hello World’教程而是一次深入ArkUI核心特性的实战演练。1. 项目准备与环境搭建在开始编码之前我们需要确保开发环境配置正确。DevEco Studio是鸿蒙应用开发的官方IDE它基于IntelliJ IDEA平台构建提供了强大的代码提示和实时预览功能。首先确保你已经安装了最新版本的DevEco Studio目前是4.0版本。安装完成后创建一个新的Empty Ability项目选择ArkTS作为开发语言。项目结构会自动生成以下关键文件src/main/ets ├── entryability │ └── EntryAbility.ts ├── pages │ └── Index.ets └── resources ├── base │ ├── element │ ├── media │ └── profile └── rawfile提示在创建项目时建议勾选Enable Super Visual选项这将允许你使用可视化布局工具对于UI开发非常有帮助。接下来我们需要分析微信‘发现’页面的结构。这个页面主要由以下几个部分组成顶部导航栏功能入口列表朋友圈、扫一扫、小程序等每个列表项的图标和文字列表项之间的分隔线2. 构建基础布局结构ArkUI采用声明式UI编程范式这意味着我们不需要直接操作DOM而是通过描述UI应该是什么样子来构建界面。微信‘发现’页面的主体是一个垂直滚动的列表我们可以使用List组件来实现。在Index.ets文件中我们先构建基础框架Entry Component struct DiscoverPage { build() { Column() { // 顶部导航栏 TitleBar({ title: 发现 }) // 主体内容区域 List({ space: 0 }) { // 列表项将在这里添加 } .width(100%) .layoutWeight(1) } .width(100%) .height(100%) .backgroundColor(#f5f5f5) } }TitleBar是一个自定义组件我们可以这样实现Component struct TitleBar { private title: string build() { Row() { Text(this.title) .fontSize(20) .fontWeight(FontWeight.Bold) .margin({ left: 16 }) } .width(100%) .height(56) .backgroundColor(#ffffff) .justifyContent(FlexAlign.Start) .alignItems(VerticalAlign.Center) } }3. 实现列表项组件微信‘发现’页面的每个列表项都有相似的结构左侧图标、中间文字描述、右侧箭头。我们可以创建一个可复用的DiscoverItem组件Component struct DiscoverItem { private icon: Resource private text: string build() { Row() { // 左侧图标 Image(this.icon) .width(24) .height(24) .margin({ left: 16, right: 16 }) // 中间文字 Text(this.text) .fontSize(16) .layoutWeight(1) // 右侧箭头 Image($r(app.media.ic_arrow_right)) .width(16) .height(16) .margin({ right: 16 }) } .width(100%) .height(56) .backgroundColor(#ffffff) .justifyContent(FlexAlign.SpaceBetween) .alignItems(VerticalAlign.Center) } }现在我们可以在主页面中使用这个组件来构建完整的列表Entry Component struct DiscoverPage { private items [ { icon: $r(app.media.ic_moments), text: 朋友圈 }, { icon: $r(app.media.ic_scan), text: 扫一扫 }, { icon: $r(app.media.ic_shake), text: 摇一摇 }, { icon: $r(app.media.ic_nearby), text: 附近的人 }, { icon: $r(app.media.ic_shopping), text: 购物 }, { icon: $r(app.media.ic_miniprogram), text: 小程序 } ] build() { Column() { TitleBar({ title: 发现 }) List({ space: 0 }) { ForEach(this.items, (item, index) { ListItem() { DiscoverItem({ icon: item.icon, text: item.text }) } .borderRadius(0) .margin({ top: index 0 ? 8 : 0 }) }) } .width(100%) .layoutWeight(1) } .width(100%) .height(100%) .backgroundColor(#f5f5f5) } }4. 添加分隔线与分组效果观察微信的‘发现’页面你会发现列表项是分组的每组之间有明显的分隔。我们可以通过添加空白列表项作为分隔线来实现这个效果。首先修改items数组private items [ { type: item, icon: $r(app.media.ic_moments), text: 朋友圈 }, { type: item, icon: $r(app.media.ic_scan), text: 扫一扫 }, { type: divider }, { type: item, icon: $r(app.media.ic_shake), text: 摇一摇 }, { type: item, icon: $r(app.media.ic_nearby), text: 附近的人 }, { type: divider }, { type: item, icon: $r(app.media.ic_shopping), text: 购物 }, { type: item, icon: $r(app.media.ic_miniprogram), text: 小程序 } ]然后修改List的构建逻辑List({ space: 0 }) { ForEach(this.items, (item, index) { if (item.type divider) { ListItem() { Divider() .strokeWidth(8) .color(#f5f5f5) } .height(8) } else { ListItem() { DiscoverItem({ icon: item.icon, text: item.text }) } .borderRadius(0) .margin({ top: index 0 ? 8 : 0 }) } }) }5. 添加点击交互效果一个好的UI不仅要有静态展示还需要有流畅的交互体验。我们可以为列表项添加点击效果Component struct DiscoverItem { private icon: Resource private text: string State private isPressed: boolean false build() { Row() { // ...原有内容不变 } .width(100%) .height(56) .backgroundColor(this.isPressed ? #eeeeee : #ffffff) .justifyContent(FlexAlign.SpaceBetween) .alignItems(VerticalAlign.Center) .onTouch((event: TouchEvent) { if (event.type TouchType.Down) { this.isPressed true } else if (event.type TouchType.Up || event.type TouchType.Cancel) { this.isPressed false } }) } }6. 实现页面跳转功能微信‘发现’页面的每个入口点击后都会跳转到相应的功能页面。我们可以使用鸿蒙的路由能力来实现这个功能。首先在MainAbility.ts中配置页面路由import router from ohos.router Entry Component struct DiscoverPage { // ...原有代码不变 private navigateTo(page: string) { router.push({ url: pages/${page}, params: { from: discover } }) } build() { Column() { // ...原有代码不变 List({ space: 0 }) { ForEach(this.items, (item, index) { if (item.type divider) { // ...分隔线代码不变 } else { ListItem() { DiscoverItem({ icon: item.icon, text: item.text, onItemClick: () this.navigateTo(item.text) }) } // ...其他属性不变 } }) } // ...其他属性不变 } // ...其他属性不变 } }然后修改DiscoverItem组件添加点击回调Component struct DiscoverItem { private icon: Resource private text: string private onItemClick: () void State private isPressed: boolean false build() { Row() { // ...原有内容不变 } // ...原有属性不变 .onClick(() { this.onItemClick() }) } }7. 优化与细节调整为了让我们的仿制品更加接近原版还需要做一些细节优化添加图标资源在resources/base/media目录下添加所有需要的图标资源调整间距和字体精确匹配微信的间距和字体大小添加状态栏适配确保在不同设备上都能正确显示实现夜间模式添加对系统主题变化的响应完整的优化后的DiscoverPage组件如下Entry Component struct DiscoverPage { StorageLink(isDarkMode) isDarkMode: boolean false private items [ { type: item, icon: $r(app.media.ic_moments), text: 朋友圈 }, { type: item, icon: $r(app.media.ic_scan), text: 扫一扫 }, { type: divider }, { type: item, icon: $r(app.media.ic_shake), text: 摇一摇 }, { type: item, icon: $r(app.media.ic_nearby), text: 附近的人 }, { type: divider }, { type: item, icon: $r(app.media.ic_shopping), text: 购物 }, { type: item, icon: $r(app.media.ic_miniprogram), text: 小程序 } ] aboutToAppear() { try { this.isDarkMode settings.getSync(isDarkMode, false) } catch (e) { console.error(Failed to get dark mode setting:, e) } } private navigateTo(page: string) { router.push({ url: pages/${page}, params: { from: discover } }) } build() { Column() { StatusBar() .backgroundColor(this.isDarkMode ? #1a1a1a : #ffffff) TitleBar({ title: 发现 }) List({ space: 0 }) { ForEach(this.items, (item, index) { if (item.type divider) { ListItem() { Divider() .strokeWidth(8) .color(this.isDarkMode ? #2a2a2a : #f5f5f5) } .height(8) } else { ListItem() { DiscoverItem({ icon: item.icon, text: item.text, isDarkMode: this.isDarkMode, onItemClick: () this.navigateTo(item.text) }) } .borderRadius(0) .margin({ top: index 0 ? 8 : 0 }) } }) } .width(100%) .layoutWeight(1) } .width(100%) .height(100%) .backgroundColor(this.isDarkMode ? #1a1a1a : #f5f5f5) .onAppear(() { this.isDarkMode settings.getSync(isDarkMode, false) }) } }8. 性能优化与最佳实践在完成基本功能后我们需要关注性能优化确保应用运行流畅列表性能优化对于长列表使用LazyForEach代替ForEach图片资源优化使用合适的图片格式和尺寸减少不必要的重绘合理使用State和Prop装饰器内存管理及时释放不再使用的资源优化后的列表实现List({ space: 0 }) { LazyForEach(this.items, (item: any, index: number) { if (item.type divider) { ListItem() { Divider() .strokeWidth(8) .color(this.isDarkMode ? #2a2a2a : #f5f5f5) } .height(8) } else { ListItem() { DiscoverItem({ icon: item.icon, text: item.text, isDarkMode: this.isDarkMode, onItemClick: () this.navigateTo(item.text) }) } .borderRadius(0) .margin({ top: index 0 ? 8 : 0 }) } }, (item: any) item.text || divider) }通过这个完整的实战项目我们不仅复现了微信发现页面的外观还深入理解了ArkUI的核心概念包括组件化开发、状态管理、路由导航等。这种从真实产品出发的学习方式能帮助开发者更快掌握鸿蒙应用开发的精髓。

更多文章