HarmonyOS应用<节气通>开发第19篇:空态页面设计

引言

空态页面是应用中不可或缺的一部分,当用户没有数据时,空态页面可以引导用户进行下一步操作。本文将介绍如何设计和实现各种空态页面,包括:

  • 列表空态
  • 搜索空态
  • 收藏空态
  • 网络错误空态
  • 个性化空态

通过本文,你将掌握如何设计优雅的空态页面。


学习目标

完成本文后,你将能够:

  • ✅ 设计列表空态页面
  • ✅ 实现搜索空态
  • ✅ 创建收藏空态
  • ✅ 处理网络错误空态
  • ✅ 添加个性化空态

需求分析

功能模块设计

模块 功能描述 技术要点
列表空态 列表无数据时的展示 图片+文字+按钮
搜索空态 搜索无结果时的展示 搜索图标+提示文字
收藏空态 收藏为空时的展示 收藏图标+引导文字
网络错误 网络异常时的展示 刷新按钮+错误提示
个性化空态 根据场景定制空态 定制图标和文案

核心实现

步骤1: 空态组件封装

完整代码
typescript 复制代码
// components/EmptyState.ets

@Component
export struct EmptyState {
  // 空态类型
  @Prop type: EmptyStateType = 'default';
  
  // 自定义标题
  @Prop title?: string;
  
  // 自定义描述
  @Prop description?: string;
  
  // 自定义按钮文字
  @Prop buttonText?: string;
  
  // 自定义按钮点击事件
  @Prop onButtonClick?: () => void;
  
  /**
   * 获取空态配置
   */
  private getConfig(): EmptyStateConfig {
    const configs: Record<EmptyStateType, EmptyStateConfig> = {
      default: {
        icon: $r('app.media.ic_empty_default'),
        title: '暂无数据',
        description: '暂无相关内容',
        buttonText: '去看看',
        backgroundColor: '#F8F7F2'
      },
      list: {
        icon: $r('app.media.ic_empty_list'),
        title: '暂无内容',
        description: '还没有相关内容,快来添加吧',
        buttonText: '添加内容',
        backgroundColor: '#FFFFFF'
      },
      search: {
        icon: $r('app.media.ic_empty_search'),
        title: '未找到结果',
        description: '换个关键词试试吧',
        buttonText: '重新搜索',
        backgroundColor: '#FFFFFF'
      },
      collect: {
        icon: $r('app.media.ic_empty_collect'),
        title: '暂无收藏',
        description: '快去收藏喜欢的内容吧',
        buttonText: '去探索',
        backgroundColor: '#FFFFFF'
      },
      network: {
        icon: $r('app.media.ic_empty_network'),
        title: '网络异常',
        description: '请检查网络连接后重试',
        buttonText: '刷新',
        backgroundColor: '#F8F7F2'
      },
      quiz: {
        icon: $r('app.media.ic_empty_quiz'),
        title: '暂无测验记录',
        description: '快去参加测验吧',
        buttonText: '去测验',
        backgroundColor: '#FFFFFF'
      },
      article: {
        icon: $r('app.media.ic_empty_article'),
        title: '暂无文章',
        description: '暂无相关文章',
        buttonText: '去浏览',
        backgroundColor: '#FFFFFF'
      }
    };
    
    return configs[this.type] || configs.default;
  }
  
  /**
   * 构建UI
   */
  build() {
    const config = this.getConfig();
    
    Column({ space: 16 }) {
      // 图标
      Image(this.title ? $r('app.media.ic_empty_default') : config.icon)
        .width(120)
        .height(120)
        .opacity(0.5)
      
      // 标题
      Text(this.title || config.title)
        .fontSize(16)
        .fontColor('#999999')
      
      // 描述
      Text(this.description || config.description)
        .fontSize(14)
        .fontColor('#BBBBBB')
      
      // 按钮
      if (this.buttonText || config.buttonText) {
        Button(this.buttonText || config.buttonText)
          .width(120)
          .height(40)
          .backgroundColor('#4A9B6D')
          .fontColor('#FFFFFF')
          .borderRadius(20)
          .margin({ top: 16 })
          .onClick(() => {
            if (this.onButtonClick) {
              this.onButtonClick();
            }
          })
      }
    }
    .width('100%')
    .height('100%')
    .backgroundColor(config.backgroundColor)
    .justifyContent(FlexAlign.Center)
  }
}

type EmptyStateType = 'default' | 'list' | 'search' | 'collect' | 'network' | 'quiz' | 'article';

interface EmptyStateConfig {
  icon: Resource;
  title: string;
  description: string;
  buttonText: string;
  backgroundColor: string;
}
代码解析

1. 空态类型

  • default: 默认空态
  • list: 列表空态
  • search: 搜索空态
  • collect: 收藏空态
  • network: 网络错误空态
  • quiz: 测验空态
  • article: 文章空态

2. 配置对象

  • icon: 图标资源
  • title: 标题文字
  • description: 描述文字
  • buttonText: 按钮文字
  • backgroundColor: 背景颜色

步骤2: 使用空态组件

typescript 复制代码
// 在页面中使用空态组件

@Entry
@Component
struct MyPage {
  @State data: any[] = [];
  @State isLoading: boolean = false;
  @State hasError: boolean = false;
  
  build() {
    Column() {
      if (this.isLoading) {
        // 加载中状态
        Column() {
          LoadingProgress().width(40).height(40)
          Text('加载中...').fontSize(14).fontColor('#999').margin({ top: 16 })
        }
        .width('100%')
        .height('100%')
        .justifyContent(FlexAlign.Center)
      } else if (this.hasError) {
        // 网络错误空态
        EmptyState({
          type: 'network',
          onButtonClick: () => {
            this.loadData();
          }
        })
      } else if (this.data.length === 0) {
        // 数据为空空态
        EmptyState({
          type: 'list',
          onButtonClick: () => {
            // 跳转到添加页面
          }
        })
      } else {
        // 正常数据展示
        List() {
          ForEach(this.data, (item) => {
            ListItem() {
              // 列表项
            }
          })
        }
      }
    }
    .width('100%')
    .height('100%')
  }
  
  loadData() {
    // 加载数据逻辑
  }
}

设计要点:

  • 根据状态展示不同的空态
  • 加载中状态
  • 网络错误状态
  • 数据为空状态

步骤3: 搜索空态

typescript 复制代码
/**
 * 搜索空态组件
 */
@Component
struct SearchEmptyState {
  @Prop keyword: string = '';
  
  build() {
    Column({ space: 16 }) {
      // 搜索图标
      Stack({ alignContent: Alignment.Center }) {
        Circle()
          .width(100)
          .height(100)
          .fillColor('#E8F5E9')
        
        Image($r('app.media.ic_search'))
          .width(40)
          .height(40)
          .fillColor('#4A9B6D')
      }
      
      // 标题
      Text(`未找到 "${this.keyword}" 相关结果`)
        .fontSize(16)
        .fontColor('#999999')
      
      // 描述
      Text('换个关键词试试吧')
        .fontSize(14)
        .fontColor('#BBBBBB')
      
      // 热门搜索标签
      Column({ space: 12 }) {
        Text('热门搜索')
          .fontSize(14)
          .fontColor('#666666')
        
        Wrap({ spacing: 8 }) {
          ['立春', '清明', '夏至', '冬至', '节气养生', '传统习俗'].forEach((tag) => {
            Text(tag)
              .fontSize(13)
              .fontColor('#4A9B6D')
              .padding({ left: 12, right: 12, top: 6, bottom: 6 })
              .backgroundColor('#E8F5E9')
              .borderRadius(20)
          })
        }
      }
      .margin({ top: 16 })
    }
    .width('100%')
    .padding(24)
  }
}

设计要点:

  • 显示搜索关键词
  • 热门搜索标签
  • 引导用户尝试其他关键词

步骤4: 网络错误空态

typescript 复制代码
/**
 * 网络错误空态组件
 */
@Component
struct NetworkErrorState {
  @Prop onRetry: () => void = () => {};
  
  build() {
    Column({ space: 16 }) {
      // 网络图标
      Stack({ alignContent: Alignment.Center }) {
        Circle()
          .width(100)
          .height(100)
          .fillColor('#FFF5F5')
        
        Image($r('app.media.ic_wifi_off'))
          .width(40)
          .height(40)
          .fillColor('#FF5252')
      }
      
      // 标题
      Text('网络连接异常')
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .fontColor('#333333')
      
      // 描述
      Text('请检查网络连接后重试')
        .fontSize(14)
        .fontColor('#999999')
      
      // 刷新按钮
      Button('刷新')
        .width(120)
        .height(44)
        .backgroundColor('#4A9B6D')
        .fontColor('#FFFFFF')
        .fontSize(16)
        .borderRadius(22)
        .onClick(() => {
          this.onRetry();
        })
      
      // 提示信息
      Text('也可以尝试离线模式')
        .fontSize(12)
        .fontColor('#BBBBBB')
        .margin({ top: 8 })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .backgroundColor('#F8F7F2')
  }
}

设计要点:

  • 红色错误主题
  • 刷新按钮
  • 离线模式提示

步骤5: 收藏空态

typescript 复制代码
/**
 * 收藏空态组件
 */
@Component
struct CollectEmptyState {
  @Prop onExplore: () => void = () => {};
  
  build() {
    Column({ space: 16 }) {
      // 收藏图标
      Stack({ alignContent: Alignment.Center }) {
        Circle()
          .width(100)
          .height(100)
          .fillColor('#FFF8E1')
        
        Image($r('app.media.ic_collect'))
          .width(40)
          .height(40)
          .fillColor('#FFB300')
      }
      
      // 标题
      Text('暂无收藏')
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .fontColor('#333333')
      
      // 描述
      Text('快去收藏喜欢的节气和文章吧')
        .fontSize(14)
        .fontColor('#999999')
      
      // 去探索按钮
      Button('去探索')
        .width(120)
        .height(44)
        .backgroundColor('#4A9B6D')
        .fontColor('#FFFFFF')
        .fontSize(16)
        .borderRadius(22)
        .onClick(() => {
          this.onExplore();
        })
      
      // 推荐内容
      Column({ space: 12 }) {
        Text('为你推荐')
          .fontSize(14)
          .fontColor('#666666')
          .alignSelf(ItemAlign.Center)
        
        Column({ space: 8 }) {
          ['立春 - 春天的开始', '清明 - 缅怀先人', '夏至 - 最长的白天'].forEach((item) => {
            Row({ space: 8 }) {
              Image($r('app.media.ic_star'))
                .width(16)
                .height(16)
                .fillColor('#FFB300')
              
              Text(item)
                .fontSize(14)
                .fontColor('#666666')
            }
          })
        }
      }
      .margin({ top: 16 })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .backgroundColor('#FFFFFF')
  }
}

设计要点:

  • 黄色主题(收藏相关)
  • 推荐内容列表
  • 引导用户去探索

本章小结

核心知识点

本文完成了空态页面的设计:

1. 空态组件封装

  • 统一的空态组件
  • 支持多种类型
  • 可自定义配置

2. 搜索空态

  • 显示搜索关键词
  • 热门搜索标签

3. 网络错误空态

  • 错误提示
  • 刷新按钮
  • 离线模式提示

4. 收藏空态

  • 推荐内容
  • 引导用户操作

系列总结

🎉 "节气通"应用开发系列文章第二篇圆满完成!

通过第二篇文章,你已经学会了:

已完成的页面 :

  1. 个人中心页开发 - 用户信息、学习统计、功能入口

  2. 设置页开发 - 基础设置、数据管理、账号安全

  3. 隐私设置与服务模式 - 权限管理、数据授权、隐私信息

  4. 收藏功能实现 - 收藏列表、添加/删除收藏

  5. 学习记录页面 - 学习统计、学习日历、成就系统

  6. 知识问答页面 - 问答列表、提问、回答功能

  7. 意见反馈页面 - 反馈表单、问题分类、图片上传

  8. 关于页面与隐私政策 - 应用介绍、版本信息、法律信息

  9. 空态页面设计 - 各种空态场景的设计


下一步预告

第二篇已经完成!在下一篇中,我们将学习:

  • 组件封装与复用
  • ArticleCard组件封装
  • HolidayCard组件封装
  • CategoryGrid组件封装
  • Timeline组件封装

节气通应用已发布上线,可在应用市场下载体验

相关链接

相关推荐
伶俜662 小时前
零基础学 ArkUI 传感器(专题二):从加速度计到指南针,玩转硬件能力
学习·华为·harmonyos
G_dou_2 小时前
Flutter三方库适配OpenHarmony【expense_tracker】消费记录器项目完整实战
flutter·harmonyos
FrameNotWork2 小时前
HarmonyOS6.1 从图像分类到目标检测的扩展实现
人工智能·harmonyos
nashane3 小时前
HarmonyOS 6商城开发学习:消息中心未读清零——@ObservedV2+@Trace驱动一键清除
学习·华为·harmonyos
yuegu7773 小时前
HarmonyOS应用<节气通>开发第16篇:知识问答页面
华为·harmonyos
●VON4 小时前
AtomGit Flutter鸿蒙客户端:鸿蒙平台集成
flutter·华为·跨平台·harmonyos·鸿蒙
●VON4 小时前
AtomGit Flutter鸿蒙客户端:共享组件
java·flutter·华为·harmonyos·鸿蒙
川石课堂软件测试4 小时前
UI自动化测试|XPath元素定位实践
功能测试·测试工具·jmeter·microsoft·ui·postman·harmonyos