首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >HarmonyOS应用开发实战 | ArkTS 容器组件综合使用指南

HarmonyOS应用开发实战 | ArkTS 容器组件综合使用指南

作者头像
红目香薰
发布2025-12-16 17:06:33
发布2025-12-16 17:06:33
1230
举报
文章被收录于专栏:CSDNToQQCodeCSDNToQQCode

? 用心打造每一个技术细节,为开发者创造更多价值 ? 让HarmonyOS开发变得更简单、更有趣


✨ 写在前面的话

嗨,亲爱的技术朋友们!?

我是来自红目香薰,一个热爱技术、专注HarmonyOS开发的程序媛。在这个数字化飞速发展的时代,HarmonyOS作为华为自主研发的操作系统,正在改变着我们的数字生活体验。

? 为什么要写这个系列?

  • ? 让复杂的技术变得简单易懂
  • ? 帮助更多开发者快速上手HarmonyOS
  • ? 分享实战经验,避免踩坑
  • ? 用代码创造美好,用技术传递温暖

每一个Demo都是我精心设计和反复测试的结果,希望能够为你的HarmonyOS开发之路点亮一盏明灯。✨

今天我们来深入学习HarmonyOS中最重要的容器组件——List、Swiper、Grid、Scroll、Tabs的综合使用。从单一组件到复杂的组合布局,让我们一起打造现代化的移动应用界面!


? Demo功能说明

img
img
? 核心功能

本Demo展示了HarmonyOS中五大核心容器组件的综合使用方法,包括:

  • ? List列表组件的多样化展示和交互
  • ? Swiper轮播组件的图片和内容轮播
  • ? Grid网格组件的瀑布流和卡片布局
  • ? Scroll滚动组件的嵌套滚动和优化
  • ? Tabs页签组件的多页面管理
  • ? 容器组件的嵌套组合和协同工作
  • ? 复杂界面的布局设计和交互优化
  • ? 实际应用场景的完整实现
✨ 特色亮点
  • ? 视觉精美:现代化的界面设计和动画效果
  • ? 交互流畅:丝滑的滚动和切换体验
  • ? 响应式设计:适配不同屏幕尺寸和方向
  • ? 功能丰富:涵盖主流应用的界面模式
  • ? 实用性强:可直接应用于实际项目开发
? 界面展示

界面采用现代化的应用设计风格:

  • 首页:轮播图 + 功能网格 + 推荐列表
  • 发现页:瀑布流网格 + 分类标签
  • 消息页:多类型消息列表 + 滑动操作
  • 我的页:个人信息 + 功能设置列表
  • 设置页:分组设置 + 嵌套滚动
? 适用场景
  • ? 电商应用的首页和商品展示
  • ? 新闻应用的内容聚合和分类
  • ?️ 社交应用的动态和消息管理
  • ⚙️ 工具应用的功能导航和设置
  • ? 数据应用的图表和列表展示
  • ? 娱乐应用的内容推荐和分类

? 核心代码说明

? 项目结构
代码语言:javascript
复制
ContainerDemo/
├── src/
│   ├── main/
│   │   ├── ets/
│   │   │   ├── pages/
│   │   │   │   └── Index.ets          // 主页面
│   │   │   └── entryability/
│   │   └── resources/
│   │       ├── base/
│   │       │   ├── element/
│   │       │   └── media/
│   │       └── rawfile/
│   └── module.json5
? 关键技术点
1. 容器组件嵌套结构
代码语言:javascript
复制
Tabs() {
  TabContent() {
    Scroll() {
      Column() {
        Swiper() { /* 轮播内容 */ }
        Grid() { /* 网格内容 */ }
        List() { /* 列表内容 */ }
      }
    }
  }
  .tabBar('首页')
}
2. 响应式布局设计
代码语言:javascript
复制
Grid() {
  // 网格项
}
.columnsTemplate('1fr 1fr 1fr')
.rowsGap(10)
.columnsGap(10)
3. 滚动性能优化
代码语言:javascript
复制
List() {
  LazyForEach(dataSource, (item) => {
    ListItem() {
      // 列表项内容
    }
  })
}
.cachedCount(3)
.scrollBar(BarState.Auto)
4. 组件间数据传递
  • @State: 组件内状态管理
  • @Prop: 父子组件数据传递
  • @Watch: 状态变化监听
? 技术要点解析

容器组件协同: 不同容器组件的嵌套使用,实现复杂的界面布局和交互效果。

性能优化策略: 通过懒加载、缓存机制、虚拟滚动等技术提升大数据量场景下的性能。

响应式适配: 根据屏幕尺寸和设备特性自动调整布局和交互方式。


? 完整Demo代码

? 主页面代码
代码语言:javascript
复制
// src/main/ets/pages/Index.ets

// 轮播数据接口
interface BannerData {
  id: number
  title: string
  image: string
  description: string
}

// 功能网格数据接口
interface FeatureData {
  id: number
  title: string
  icon: string
  color: string
  route?: string
}

// 商品数据接口
interface ProductData {
  id: number
  title: string
  price: number
  originalPrice?: number
  image: string
  tag?: string
  rating: number
}

// 消息数据接口
interface MessageData {
  id: number
  type: 'system' | 'user' | 'order' | 'activity'
  title: string
  content: string
  time: string
  avatar?: string
  unread: boolean
}

// 设置项数据接口
interface SettingData {
  id: number
  title: string
  subtitle?: string
  icon: string
  type: 'switch' | 'arrow' | 'info'
  value?: boolean
}

@Entry
@Component
struct ContainerDemo {
  @State currentTabIndex: number = 0
  @State swiperIndex: number = 0
  @State refreshing: boolean = false

  // 轮播数据
  private bannerData: BannerData[] = [
    { id: 1, title: '夏日特惠', image: '?️', description: '全场商品5折起,限时抢购' },
    { id: 2, title: '新品上市', image: '?', description: '最新款式,引领时尚潮流' },
    { id: 3, title: '品质生活', image: '?', description: '精选好物,提升生活品质' },
    { id: 4, title: '会员专享', image: '?', description: '会员专属优惠,尊享特权' }
  ]

  // 功能网格数据
  private featureData: FeatureData[] = [
    { id: 1, title: '每日签到', icon: '?', color: '#FF6B6B' },
    { id: 2, title: '积分商城', icon: '?', color: '#4ECDC4' },
    { id: 3, title: '优惠券', icon: '?', color: '#45B7D1' },
    { id: 4, title: '客服中心', icon: '?', color: '#96CEB4' },
    { id: 5, title: '邀请好友', icon: '?', color: '#FFEAA7' },
    { id: 6, title: '意见反馈', icon: '?', color: '#DDA0DD' },
    { id: 7, title: '关于我们', icon: 'ℹ️', color: '#98D8C8' },
    { id: 8, title: '更多功能', icon: '⋯', color: '#F7DC6F' }
  ]

  // 商品数据
  private productData: ProductData[] = [
    { id: 1, title: '时尚休闲鞋', price: 299, originalPrice: 399, image: '?', tag: '热销', rating: 4.8 },
    { id: 2, title: '简约T恤', price: 89, originalPrice: 129, image: '?', tag: '新品', rating: 4.6 },
    { id: 3, title: '舒适牛仔裤', price: 199, originalPrice: 259, image: '?', tag: '推荐', rating: 4.7 },
    { id: 4, title: '时尚手表', price: 599, originalPrice: 799, image: '⌚', tag: '限时', rating: 4.9 },
    { id: 5, title: '潮流背包', price: 159, originalPrice: 199, image: '?', tag: '热销', rating: 4.5 },
    { id: 6, title: '运动鞋', price: 399, originalPrice: 499, image: '?', tag: '新品', rating: 4.8 }
  ]

  // 消息数据
  private messageData: MessageData[] = [
    { id: 1, type: 'system', title: '系统通知', content: '您的订单已发货,请注意查收', time: '2分钟前', unread: true },
    { id: 2, type: 'activity', title: '活动消息', content: '双十一活动即将开始,敬请期待', time: '1小时前', unread: true },
    { id: 3, type: 'order', title: '订单消息', content: '您的订单已完成,感谢您的购买', time: '3小时前', unread: false },
    { id: 4, type: 'user', title: '用户消息', content: '您有新的好友申请', time: '1天前', unread: false },
    { id: 5, type: 'system', title: '系统维护', content: '系统将于今晚进行维护升级', time: '2天前', unread: false }
  ]

  // 设置数据
  private settingData: SettingData[] = [
    { id: 1, title: '消息推送', subtitle: '接收系统通知', icon: '?', type: 'switch', value: true },
    { id: 2, title: '隐私设置', subtitle: '管理个人隐私', icon: '?', type: 'arrow' },
    { id: 3, title: '账户安全', subtitle: '密码和安全设置', icon: '?️', type: 'arrow' },
    { id: 4, title: '语言设置', subtitle: '中文简体', icon: '?', type: 'arrow' },
    { id: 5, title: '清除缓存', subtitle: '128MB', icon: '?️', type: 'arrow' },
    { id: 6, title: '版本信息', subtitle: 'v1.0.0', icon: 'ℹ️', type: 'info' }
  ]

  build() {
    Column() {
      this.buildHeader()
      Tabs({ barPosition: BarPosition.End, index: this.currentTabIndex }) {
        TabContent() {
          this.buildHomePage()
        }
        .tabBar(this.buildTabBar(0, '首页', '?'))

        TabContent() {
          this.buildDiscoverPage()
        }
        .tabBar(this.buildTabBar(1, '发现', '?'))

        TabContent() {
          this.buildMessagePage()
        }
        .tabBar(this.buildTabBar(2, '消息', '?'))

        TabContent() {
          this.buildProfilePage()
        }
        .tabBar(this.buildTabBar(3, '我的', '?'))
      }
      .layoutWeight(1)
      .barBackgroundColor('#FFFFFF')
      .barHeight(80)
      .animationDuration(300)
      .onChange((index: number) => {
        this.currentTabIndex = index
      })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }

  @Builder
  buildHeader() {
    Row({ space: 15 }) {
      Text('?')
        .fontSize(24)
      Text('容器组件综合示例')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor(Color.White)
        .layoutWeight(1)
      Text('?')
        .fontSize(20)
        .fontColor(Color.White)
        .onClick(() => {
          console.log('Search clicked')
        })
      Text('⋯')
        .fontSize(20)
        .fontColor(Color.White)
        .onClick(() => {
          console.log('More clicked')
        })
    }
    .width('100%')
    .height(60)
    .padding({ left: 20, right: 20 })
    .backgroundColor('#667eea')
    .shadow({
      radius: 8,
      color: '#30000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  @Builder
  buildTabBar(index: number, title: string, icon: string) {
    Column({ space: 5 }) {
      Stack({ alignContent: Alignment.TopEnd }) {
        Text(icon)
          .fontSize(24)
          .fontColor(this.currentTabIndex === index ? '#667eea' : '#999999')
        if (index === 2 && this.getUnreadCount() > 0) {
          Text(this.getUnreadCount().toString())
            .fontSize(10)
            .fontColor(Color.White)
            .backgroundColor('#FF4444')
            .borderRadius(8)
            .padding({ left: 4, right: 4, top: 1, bottom: 1 })
            .margin({ top: -5, right: -5 })
        }
      }
      Text(title)
        .fontSize(12)
        .fontColor(this.currentTabIndex === index ? '#667eea' : '#999999')
        .fontWeight(this.currentTabIndex === index ? FontWeight.Medium : FontWeight.Normal)
    }
    .width(60)
    .height(60)
    .justifyContent(FlexAlign.Center)
  }

  @Builder
  buildHomePage() {
    Scroll() {
      Column({ space: 0 }) {
        this.buildBannerSwiper()
        this.buildFeatureGrid()
        this.buildRecommendList()
      }
    }
    .width('100%')
    .height('100%')
    .scrollBar(BarState.Auto)
    .edgeEffect(EdgeEffect.Spring)
  }

  @Builder
  buildDiscoverPage() {
    Column() {
      this.buildCategoryTabs()
      this.buildProductGrid()
    }
    .width('100%')
    .height('100%')
  }

  @Builder
  buildMessagePage() {
    Column() {
      this.buildMessageHeader()
      this.buildMessageList()
    }
    .width('100%')
    .height('100%')
  }

  @Builder
  buildProfilePage() {
    Scroll() {
      Column({ space: 20 }) {
        this.buildUserInfo()
        this.buildSettingList()
      }
    }
    .width('100%')
    .height('100%')
    .scrollBar(BarState.Auto)
    .backgroundColor('#F8F9FA')
  }

  @Builder
  buildBannerSwiper() {
    Swiper() {
      ForEach(this.bannerData, (banner: BannerData) => {
        Stack({ alignContent: Alignment.BottomStart }) {
          Column() {
            Text(banner.image)
              .fontSize(80)
            Text(banner.title)
              .fontSize(24)
              .fontWeight(FontWeight.Bold)
              .fontColor('#333333')
              .margin({ top: 20 })
          }
          .width('100%')
          .height(200)
          .backgroundColor('#FFFFFF')
          .borderRadius(15)
          .justifyContent(FlexAlign.Center)
          .shadow({
            radius: 10,
            color: '#20000000',
            offsetX: 0,
            offsetY: 5
          })
          .margin({ left: 20, right: 20 })

          Column({ space: 5 }) {
            Text(banner.title)
              .fontSize(18)
              .fontWeight(FontWeight.Bold)
              .fontColor(Color.White)
            Text(banner.description)
              .fontSize(14)
              .fontColor('#FFFFFF')
              .opacity(0.9)
          }
          .alignItems(HorizontalAlign.Start)
          .padding(20)
          .width('100%')
          .borderRadius({ bottomLeft: 15, bottomRight: 15 })
          .linearGradient({
            angle: 180,
            colors: [['#00000000', 0.0], ['#80000000', 1.0]]
          })
        }
      })
    }
    .width('100%')
    .height(240)
    .autoPlay(true)
    .interval(3000)
    .indicator(true)
    .loop(true)
    .duration(500)
    .indicatorStyle({
      bottom: 20,
      right: 20,
      color: '#80FFFFFF',
      selectedColor: '#FFFFFF'
    })
    .onChange((index: number) => {
      this.swiperIndex = index
    })
    .margin({ top: 10, bottom: 20 })
  }

  @Builder
  buildFeatureGrid() {
    Column({ space: 15 }) {
      Row() {
        Text('? 快捷功能')
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor('#333333')
          .layoutWeight(1)
        Text('更多 >')
          .fontSize(14)
          .fontColor('#666666')
          .onClick(() => {
            console.log('More features clicked')
          })
      }
      .width('100%')
      .padding({ left: 20, right: 20 })

      Grid() {
        ForEach(this.featureData, (feature: FeatureData) => {
          GridItem() {
            this.buildFeatureCard(feature)
          }
        })
      }
      .columnsTemplate('1fr 1fr 1fr 1fr')
      .rowsTemplate('1fr 1fr')
      .columnsGap(15)
      .rowsGap(15)
      .width('100%')
      .height(180)
      .padding({ left: 20, right: 20 })
    }
    .width('100%')
    .backgroundColor(Color.White)
    .padding({ top: 20, bottom: 20 })
    .margin({ bottom: 10 })
  }

  @Builder
  buildRecommendList() {
    Column({ space: 15 }) {
      Row() {
        Text('? 热门推荐')
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor('#333333')
          .layoutWeight(1)
        Text('查看全部 >')
          .fontSize(14)
          .fontColor('#666666')
          .onClick(() => {
            console.log('View all products clicked')
          })
      }
      .width('100%')
      .padding({ left: 20, right: 20 })

      List({ space: 10 }) {
        ForEach(this.productData, (product: ProductData) => {
          ListItem() {
            this.buildProductCard(product)
          }
        })
      }
      .width('100%')
      .height(300)
      .padding({ left: 20, right: 20 })
    }
    .width('100%')
    .backgroundColor(Color.White)
    .padding({ top: 20, bottom: 20 })
  }

  @Builder
  buildCategoryTabs() {
    Tabs({ barPosition: BarPosition.Start }) {
      TabContent() {
        this.buildCategoryContent('全部')
      }
      .tabBar('全部')

      TabContent() {
        this.buildCategoryContent('服装')
      }
      .tabBar('服装')

      TabContent() {
        this.buildCategoryContent('数码')
      }
      .tabBar('数码')

      TabContent() {
        this.buildCategoryContent('家居')
      }
      .tabBar('家居')

      TabContent() {
        this.buildCategoryContent('美妆')
      }
      .tabBar('美妆')
    }
    .width('100%')
    .layoutWeight(1)
    .barBackgroundColor('#FFFFFF')
    .barHeight(50)
    .scrollable(true)
    .animationDuration(200)
  }

  @Builder
  buildProductGrid() {
    Grid() {
      ForEach(this.productData, (product: ProductData) => {
        GridItem() {
          this.buildGridProductCard(product)
        }
      })
    }
    .columnsTemplate('1fr 1fr')
    .columnsGap(10)
    .rowsGap(10)
    .width('100%')
    .layoutWeight(1)
    .padding(10)
    .backgroundColor('#F8F9FA')
  }

  @Builder
  buildMessageHeader() {
    Row({ space: 15 }) {
      Text('?')
        .fontSize(24)
      Text('消息中心')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor('#333333')
        .layoutWeight(1)
      Text('全部已读')
        .fontSize(14)
        .fontColor('#667eea')
        .onClick(() => {
          this.markAllAsRead()
        })
    }
    .width('100%')
    .height(60)
    .padding({ left: 20, right: 20 })
    .backgroundColor(Color.White)
    .shadow({
      radius: 5,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
  }

  @Builder
  buildMessageList() {
    List({ space: 1 }) {
      ForEach(this.messageData, (message: MessageData) => {
        ListItem() {
          this.buildMessageItem(message)
        }
        .swipeAction({ end: this.buildSwipeAction(message) })
      })
    }
    .width('100%')
    .layoutWeight(1)
    .backgroundColor('#F8F9FA')
    .divider({
      strokeWidth: 1,
      color: '#F0F0F0',
      startMargin: 70,
      endMargin: 20
    })
  }

  @Builder
  buildUserInfo() {
    Row({ space: 20 }) {
      Text('?')
        .fontSize(60)
        .backgroundColor('#E3F2FD')
        .borderRadius(30)
        .padding(15)
      Column({ space: 8 }) {
        Text('用户昵称')
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .fontColor('#333333')
        Text('user@example.com')
          .fontSize(14)
          .fontColor('#666666')
        Row({ space: 10 }) {
          Text('会员等级: VIP')
            .fontSize(12)
            .fontColor('#FF6B6B')
            .backgroundColor('#FFE5E5')
            .padding({ left: 8, right: 8, top: 4, bottom: 4 })
            .borderRadius(10)
          Text('积分: 1280')
            .fontSize(12)
            .fontColor('#4ECDC4')
            .backgroundColor('#E5F9F6')
            .padding({ left: 8, right: 8, top: 4, bottom: 4 })
            .borderRadius(10)
        }
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)
    }
    .width('100%')
    .padding(20)
    .backgroundColor(Color.White)
    .borderRadius(15)
    .shadow({
      radius: 10,
      color: '#20000000',
      offsetX: 0,
      offsetY: 5
    })
    .margin({ left: 20, right: 20, top: 20 })
  }

  @Builder
  buildSettingList() {
    Column({ space: 15 }) {
      Text('⚙️ 设置选项')
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .fontColor('#333333')
        .alignSelf(ItemAlign.Start)
        .margin({ left: 20 })

      List({ space: 1 }) {
        ForEach(this.settingData, (setting: SettingData) => {
          ListItem() {
            this.buildSettingItem(setting)
          }
        })
      }
      .width('100%')
      .backgroundColor(Color.White)
      .borderRadius(15)
      .margin({ left: 20, right: 20 })
      .shadow({
        radius: 5,
        color: '#20000000',
        offsetX: 0,
        offsetY: 2
      })
    }
  }

  @Builder
  buildFeatureCard(feature: FeatureData) {
    Column({ space: 10 }) {
      Text(feature.icon)
        .fontSize(28)
        .fontColor(feature.color)
      Text(feature.title)
        .fontSize(12)
        .fontColor('#333333')
        .fontWeight(FontWeight.Medium)
    }
    .width('100%')
    .height('100%')
    .backgroundColor(Color.White)
    .borderRadius(12)
    .justifyContent(FlexAlign.Center)
    .shadow({
      radius: 5,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
    .onClick(() => {
      console.log('Feature clicked:', feature.title)
    })
  }

  @Builder
  buildProductCard(product: ProductData) {
    Column({ space: 10 }) {
      Stack({ alignContent: Alignment.TopEnd }) {
        Text(product.image)
          .fontSize(40)
          .width(120)
          .height(80)
          .backgroundColor('#F8F9FA')
          .borderRadius(8)
          .textAlign(TextAlign.Center)
        if (product.tag) {
          Text(product.tag)
            .fontSize(10)
            .fontColor(Color.White)
            .backgroundColor('#FF4444')
            .padding({ left: 6, right: 6, top: 2, bottom: 2 })
            .borderRadius(8)
            .margin({ top: 5, right: 5 })
        }
      }
      Column({ space: 5 }) {
        Text(product.title)
          .fontSize(14)
          .fontWeight(FontWeight.Medium)
          .fontColor('#333333')
          .maxLines(1)
        Row({ space: 5 }) {
          Text(`¥${product.price}`)
            .fontSize(16)
            .fontWeight(FontWeight.Bold)
            .fontColor('#FF4444')
          if (product.originalPrice) {
            Text(`¥${product.originalPrice}`)
              .fontSize(12)
              .fontColor('#999999')
              .decoration({ type: TextDecorationType.LineThrough })
          }
        }
        .alignItems(VerticalAlign.Bottom)
        Row({ space: 3 }) {
          Text('⭐')
            .fontSize(12)
          Text(product.rating.toString())
            .fontSize(12)
            .fontColor('#666666')
        }
      }
      .alignItems(HorizontalAlign.Start)
    }
    .width(120)
    .padding(10)
    .backgroundColor(Color.White)
    .borderRadius(12)
    .shadow({
      radius: 5,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
    .onClick(() => {
      console.log('Product clicked:', product.title)
    })
  }

  @Builder
  buildGridProductCard(product: ProductData) {
    Column({ space: 10 }) {
      Stack({ alignContent: Alignment.TopEnd }) {
        Text(product.image)
          .fontSize(60)
          .width('100%')
          .height(120)
          .backgroundColor('#F8F9FA')
          .borderRadius(8)
          .textAlign(TextAlign.Center)
        if (product.tag) {
          Text(product.tag)
            .fontSize(10)
            .fontColor(Color.White)
            .backgroundColor('#FF4444')
            .padding({ left: 6, right: 6, top: 2, bottom: 2 })
            .borderRadius(8)
            .margin({ top: 8, right: 8 })
        }
      }
      Column({ space: 8 }) {
        Text(product.title)
          .fontSize(14)
          .fontWeight(FontWeight.Medium)
          .fontColor('#333333')
          .maxLines(2)
          .textOverflow({ overflow: TextOverflow.Ellipsis })
        Row({ space: 8 }) {
          Text(`¥${product.price}`)
            .fontSize(16)
            .fontWeight(FontWeight.Bold)
            .fontColor('#FF4444')
          if (product.originalPrice) {
            Text(`¥${product.originalPrice}`)
              .fontSize(12)
              .fontColor('#999999')
              .decoration({ type: TextDecorationType.LineThrough })
          }
        }
        .alignItems(VerticalAlign.Bottom)
        Row({ space: 5 }) {
          Text('⭐')
            .fontSize(12)
          Text(product.rating.toString())
            .fontSize(12)
            .fontColor('#666666')
          Text(`(${Math.floor(Math.random() * 1000)}+)`)
            .fontSize(10)
            .fontColor('#999999')
        }
      }
      .alignItems(HorizontalAlign.Start)
      .width('100%')
    }
    .width('100%')
    .padding(10)
    .backgroundColor(Color.White)
    .borderRadius(12)
    .shadow({
      radius: 5,
      color: '#20000000',
      offsetX: 0,
      offsetY: 2
    })
    .onClick(() => {
      console.log('Grid product clicked:', product.title)
    })
  }

  @Builder
  buildCategoryContent(category: string) {
    Scroll() {
      Grid() {
        ForEach(this.productData.filter((_, index) => index % 3 !== 0), (product: ProductData) => {
          GridItem() {
            this.buildGridProductCard(product)
          }
        })
      }
      .columnsTemplate('1fr 1fr')
      .columnsGap(10)
      .rowsGap(10)
      .width('100%')
      .padding(10)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F8F9FA')
  }

  @Builder
  buildMessageItem(message: MessageData) {
    Row({ space: 15 }) {
      Stack({ alignContent: Alignment.TopEnd }) {
        Text(this.getMessageIcon(message.type))
          .fontSize(24)
          .width(50)
          .height(50)
          .backgroundColor(this.getMessageBgColor(message.type))
          .borderRadius(25)
          .textAlign(TextAlign.Center)
        if (message.unread) {
          Text('')
            .width(12)
            .height(12)
            .backgroundColor('#FF4444')
            .borderRadius(6)
            .margin({ top: 2, right: 2 })
        }
      }
      Column({ space: 8 }) {
        Row() {
          Text(message.title)
            .fontSize(16)
            .fontWeight(message.unread ? FontWeight.Bold : FontWeight.Medium)
            .fontColor('#333333')
            .layoutWeight(1)
          Text(message.time)
            .fontSize(12)
            .fontColor('#999999')
        }
        .width('100%')
        Text(message.content)
          .fontSize(14)
          .fontColor('#666666')
          .maxLines(2)
          .textOverflow({ overflow: TextOverflow.Ellipsis })
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)
    }
    .width('100%')
    .padding(15)
    .backgroundColor(message.unread ? '#F8F9FF' : Color.White)
    .onClick(() => {
      this.markMessageAsRead(message.id)
    })
  }

  @Builder
  buildSwipeAction(message: MessageData) {
    Row({ space: 10 }) {
      Button('标记已读')
        .width(80)
        .height(60)
        .backgroundColor('#4ECDC4')
        .fontColor(Color.White)
        .fontSize(12)
        .onClick(() => {
          this.markMessageAsRead(message.id)
        })
      Button('删除')
        .width(60)
        .height(60)
        .backgroundColor('#FF4444')
        .fontColor(Color.White)
        .fontSize(12)
        .onClick(() => {
          this.deleteMessage(message.id)
        })
    }
  }

  @Builder
  buildSettingItem(setting: SettingData) {
    Row({ space: 15 }) {
      Text(setting.icon)
        .fontSize(20)
        .width(30)
        .textAlign(TextAlign.Center)
      Column({ space: 5 }) {
        Text(setting.title)
          .fontSize(16)
          .fontColor('#333333')
        if (setting.subtitle) {
          Text(setting.subtitle)
            .fontSize(14)
            .fontColor('#666666')
        }
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)
      if (setting.type === 'switch') {
        Toggle({ type: ToggleType.Switch, isOn: setting.value || false })
          .selectedColor('#667eea')
          .onChange((isOn: boolean) => {
            this.updateSettingValue(setting.id, isOn)
          })
      } else if (setting.type === 'arrow') {
        Text('>')
          .fontSize(16)
          .fontColor('#C0C0C0')
      }
    }
    .width('100%')
    .height(60)
    .padding({ left: 15, right: 15 })
    .onClick(() => {
      if (setting.type === 'arrow') {
        console.log('Setting clicked:', setting.title)
      }
    })
  }

  // 工具方法
  getUnreadCount(): number {
    return this.messageData.filter(msg => msg.unread).length
  }

  getMessageIcon(type: string): string {
    switch (type) {
      case 'system': return '?'
      case 'activity': return '?'
      case 'order': return '?'
      case 'user': return '?'
      default: return '?'
    }
  }

  getMessageBgColor(type: string): string {
    switch (type) {
      case 'system': return '#E3F2FD'
      case 'activity': return '#FFF3E0'
      case 'order': return '#E8F5E8'
      case 'user': return '#F3E5F5'
      default: return '#F5F5F5'
    }
  }

  markMessageAsRead(messageId: number) {
    const index = this.messageData.findIndex(msg => msg.id === messageId)
    if (index !== -1) {
      this.messageData[index].unread = false
    }
  }

  markAllAsRead() {
    this.messageData.forEach(msg => {
      msg.unread = false
    })
  }

  deleteMessage(messageId: number) {
    const index = this.messageData.findIndex(msg => msg.id === messageId)
    if (index !== -1) {
      this.messageData.splice(index, 1)
    }
  }

  updateSettingValue(settingId: number, value: boolean) {
    const index = this.settingData.findIndex(setting => setting.id === settingId)
    if (index !== -1) {
      this.settingData[index].value = value
    }
  }
}
⚙️ 配置文件
代码语言:javascript
复制
// module.json5 配置
{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
    "deviceTypes": [
      "phone",
      "tablet"
    ],
    "deliveryWithInstall": true,
    "installationFree": false,
    "pages": "$profile:main_pages",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ts",
        "description": "$string:EntryAbility_desc",
        "icon": "$media:icon",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:icon",
        "startWindowBackground": "$color:start_window_background"
      }
    ]
  }
}

? 运行效果

? 界面展示

运行后的界面将展示:

  • ? 现代化设计:渐变色标题栏和精美的卡片设计
  • ? 底部导航:四个主要功能页面的标签切换
  • ? 首页展示:轮播图 + 功能网格 + 推荐列表的完整布局
  • ? 发现页面:分类标签 + 瀑布流网格的商品展示
  • ? 消息中心:多类型消息列表 + 滑动操作功能
  • ? 个人中心:用户信息 + 设置列表的个人页面
✅ 功能验证
  1. 轮播切换:观察Banner自动轮播和指示器变化
  2. 网格交互:点击功能网格和商品网格的响应
  3. 列表滚动:水平和垂直列表的滚动体验
  4. 页签切换:底部导航和顶部分类标签的切换
  5. 滑动操作:消息列表的左滑删除和标记功能
  6. 嵌套滚动:多层容器的滚动协调和性能

? 开发小贴士

? 最佳实践
  • ? 容器嵌套:合理规划容器层级,避免过度嵌套影响性能
  • ? 布局协调:确保不同容器组件间的布局协调和视觉统一
  • 性能优化:使用LazyForEach和缓存机制优化大数据量场景
  • ? 响应式设计:根据屏幕尺寸动态调整网格列数和布局
? 常见问题
  1. 滚动冲突:嵌套滚动容器时注意滚动方向和事件处理
  2. 内存泄漏:及时清理不需要的数据和监听器
  3. 布局错乱:确保容器尺寸设置正确,避免内容溢出
  4. 性能卡顿:优化复杂布局和动画,减少不必要的重绘
? 扩展学习
  • 虚拟滚动:学习LazyForEach的高级用法和性能优化
  • 自定义组件:创建可复用的容器组件和布局模板
  • 动画效果:为容器切换添加流畅的过渡动画

? 总结与展望

通过这个Demo,我们学习了:

  • ✨ 五大核心容器组件的综合使用和协同工作
  • ? 现代化移动应用界面的设计和实现方法
  • ? 容器组件嵌套和性能优化的开发技巧
  • ? 复杂交互和动画效果的实现原理

容器组件是构建现代移动应用界面的基础,掌握它们的综合使用对于创建优秀的用户体验至关重要。从简单的列表展示到复杂的多层嵌套布局,每一个细节都体现着应用的专业性和用户友好性。

这个综合示例涵盖了主流应用的常见界面模式,可以作为实际项目开发的参考模板。通过合理的组件组合和优化策略,我们能够创建出既美观又高效的移动应用界面。

希望这个示例能够帮助到正在学习HarmonyOS开发的你!下一期我们将探索更多高级组件和开发技巧,敬请期待!如果你有任何问题或建议,欢迎在评论区留言交流。


? 相关资源


? 如果这篇文章对你有帮助,请点赞支持!?

让我们一起在HarmonyOS的世界里创造更多可能!


© 2025 红目香薰 | 用心分享,用技术创造价值

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-11-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ✨ 写在前面的话
  • ? Demo功能说明
    • ? 核心功能
    • ✨ 特色亮点
    • ? 界面展示
    • ? 适用场景
  • ? 核心代码说明
    • ? 项目结构
    • ? 关键技术点
      • 1. 容器组件嵌套结构
      • 2. 响应式布局设计
      • 3. 滚动性能优化
      • 4. 组件间数据传递
    • ? 技术要点解析
  • ? 完整Demo代码
    • ? 主页面代码
    • ⚙️ 配置文件
  • ? 运行效果
    • ? 界面展示
    • ✅ 功能验证
  • ? 开发小贴士
    • ? 最佳实践
    • ? 常见问题
    • ? 扩展学习
  • ? 总结与展望
  • ? 相关资源
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档