[HarmonyOS NEXT 实战案例十] 电子书网格布局(上)

简介: 本教程将详细讲解如何使用HarmonyOS NEXT中的GridRow和GridCol组件实现电子书网格布局。通过网格布局,我们可以以美观、规整的方式展示各种电子书信息,为用户提供良好的浏览体验。

[HarmonyOS NEXT 实战案例十] 电子书网格布局(上)

项目已开源,开源地址: https://gitcode.com/nutpi/HarmonyosNextCaseStudyTutorial , 欢迎fork & star

效果演示

image.png

1. 概述

本教程将详细讲解如何使用HarmonyOS NEXT中的GridRow和GridCol组件实现电子书网格布局。通过网格布局,我们可以以美观、规整的方式展示各种电子书信息,为用户提供良好的浏览体验。

本教程将涵盖以下内容:

  • 电子书数据结构设计
  • 数据准备
  • 整体布局实现
  • GridRow和GridCol组件配置
  • 电子书卡片实现
  • 布局效果分析

2. 数据结构设计

首先,我们需要定义电子书的数据结构,包含电子书的基本信息:

// 电子书数据类型
export interface BookType {
   
  id: number;         // 书籍ID
  title: string;      // 书名
  cover: Resource;    // 封面图片
  author: string;     // 作者
  category: string;   // 分类
  rating: number;     // 评分
  price: number;      // 价格
  isFree: boolean;    // 是否免费
  isNew: boolean;     // 是否新书
  description: string; // 简介
}

3. 数据准备

接下来,我们准备一些示例数据用于展示:

// 电子书数据
private books: BookType[] = [
  {
   
    id: 1,
    title: '人工智能导论',
    cover: $r('app.media.book_ai'),
    author: '李明',
    category: '计算机',
    rating: 4.8,
    price: 68,
    isFree: false,
    isNew: true,
    description: '本书全面介绍了人工智能的基本概念、发展历史、核心技术和应用领域,适合人工智能初学者阅读。'
  },
  {
   
    id: 2,
    title: '数据结构与算法',
    cover: $r('app.media.book_algorithm'),
    author: '张伟',
    category: '计算机',
    rating: 4.9,
    price: 78,
    isFree: false,
    isNew: false,
    description: '本书详细讲解了常用的数据结构和算法,包括数组、链表、栈、队列、树、图、排序和搜索算法等。'
  },
  {
   
    id: 3,
    title: '深度学习实战',
    cover: $r('app.media.book_deep_learning'),
    author: '王芳',
    category: '计算机',
    rating: 4.7,
    price: 88,
    isFree: false,
    isNew: true,
    description: '本书通过实际案例讲解深度学习的原理和应用,包括神经网络、卷积神经网络、循环神经网络等。'
  },
  {
   
    id: 4,
    title: '经济学原理',
    cover: $r('app.media.book_economics'),
    author: '刘强',
    category: '经济',
    rating: 4.6,
    price: 0,
    isFree: true,
    isNew: false,
    description: '本书介绍了经济学的基本原理和概念,包括供需关系、市场结构、宏观经济政策等。'
  },
  {
   
    id: 5,
    title: '心理学入门',
    cover: $r('app.media.book_psychology'),
    author: '陈静',
    category: '心理',
    rating: 4.5,
    price: 58,
    isFree: false,
    isNew: false,
    description: '本书介绍了心理学的基本理论和研究方法,包括认知心理学、发展心理学、社会心理学等。'
  },
  {
   
    id: 6,
    title: '现代文学赏析',
    cover: $r('app.media.book_literature'),
    author: '赵红',
    category: '文学',
    rating: 4.4,
    price: 0,
    isFree: true,
    isNew: false,
    description: '本书精选了现代文学作品进行赏析,包括小说、诗歌、散文等多种体裁。'
  },
  {
   
    id: 7,
    title: '健康生活指南',
    cover: $r('app.media.book_health'),
    author: '孙健',
    category: '健康',
    rating: 4.3,
    price: 48,
    isFree: false,
    isNew: true,
    description: '本书提供了健康生活的指导和建议,包括饮食、运动、心理健康等方面。'
  },
  {
   
    id: 8,
    title: '旅行摄影技巧',
    cover: $r('app.media.book_photography'),
    author: '吴光',
    category: '摄影',
    rating: 4.7,
    price: 68,
    isFree: false,
    isNew: false,
    description: '本书介绍了旅行摄影的技巧和方法,包括构图、光线、后期处理等方面。'
  },
  {
   
    id: 9,
    title: '烹饪艺术',
    cover: $r('app.media.book_cooking'),
    author: '郑厨',
    category: '美食',
    rating: 4.8,
    price: 0,
    isFree: true,
    isNew: true,
    description: '本书介绍了烹饪的基本技巧和方法,包括中餐、西餐、甜点等多种菜系。'
  },
  {
   
    id: 10,
    title: '投资理财基础',
    cover: $r('app.media.book_finance'),
    author: '黄金',
    category: '金融',
    rating: 4.5,
    price: 58,
    isFree: false,
    isNew: false,
    description: '本书介绍了投资理财的基本知识和方法,包括股票、基金、债券等投资工具。'
  }
];

4. 布局实现

4.1 整体布局结构

我们将使用Column作为最外层容器,包含顶部搜索栏、分类标签栏和电子书网格列表:

build() {
   
  Column() {
   
    // 顶部搜索栏
    this.SearchBar()

    // 分类标签栏
    this.CategoryTabs()

    // 电子书网格列表
    this.BookGrid()
  }
  .width('100%')
  .height('100%')
  .backgroundColor('#F5F5F5')
}

4.2 顶部搜索栏

@Builder
private SearchBar() {
   
  Row() {
   
    // 搜索框
    Row() {
   
      Image($r('app.media.ic_search'))
        .width(20)
        .height(20)
        .margin({
    right: 8 })

      TextInput({
    placeholder: '搜索书名、作者' })
        .layoutWeight(1)
        .backgroundColor('transparent')
        .placeholderColor('#999999')
        .fontSize(14)
        .height('100%')
    }
    .width('85%')
    .height(40)
    .backgroundColor(Color.White)
    .borderRadius(20)
    .padding({
    left: 12, right: 12 })

    // 筛选按钮
    Image($r('app.media.ic_filter'))
      .width(24)
      .height(24)
      .margin({
    left: 12 })
  }
  .width('100%')
  .padding({
    left: 16, right: 16, top: 12, bottom: 12 })
  .backgroundColor('#673AB7')
}

4.3 分类标签栏

@State currentCategory: string = '推荐';
private categories: string[] = ['推荐', '计算机', '经济', '文学', '心理', '健康', '摄影', '美食', '金融'];

@Builder
private CategoryTabs() {
   
  Scroll(ScrollDirection.Horizontal) {
   
    Row() {
   
      ForEach(this.categories, (category: string) => {
   
        Text(category)
          .fontSize(14)
          .fontColor(this.currentCategory === category ? '#673AB7' : '#666666')
          .fontWeight(this.currentCategory === category ? FontWeight.Bold : FontWeight.Normal)
          .padding({
    left: 16, right: 16, top: 12, bottom: 12 })
          .backgroundColor(this.currentCategory === category ? '#EDE7F6' : 'transparent')
          .borderRadius(16)
          .margin({
    right: 8 })
          .onClick(() => {
   
            this.currentCategory = category;
          })
      })
    }
    .padding({
    left: 16, right: 16 })
  }
  .scrollBar(BarState.Off)
  .width('100%')
}

4.4 电子书网格列表

这是本教程的核心部分,我们使用GridRow和GridCol组件实现电子书网格列表:

@Builder
private BookGrid() {
   
  Scroll() {
   
    Column() {
   
      // 新书上架标题
      Row() {
   
        Text('新书上架')
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor('#333333')

        Blank()

        Text('查看更多 >')
          .fontSize(14)
          .fontColor('#673AB7')
      }
      .width('100%')
      .padding({
    left: 16, right: 16, top: 16, bottom: 8 })

      // 新书上架横向滚动列表
      Scroll(ScrollDirection.Horizontal) {
   
        Row() {
   
          ForEach(this.getNewBooks(), (book: BookType) => {
   
            this.NewBookCard(book)
          })
        }
        .padding({
    left: 16, right: 16 })
      }
      .scrollBar(BarState.Off)
      .width('100%')
      .margin({
    bottom: 16 })

      // 免费好书标题
      Row() {
   
        Text('免费好书')
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor('#333333')

        Blank()

        Text('查看更多 >')
          .fontSize(14)
          .fontColor('#673AB7')
      }
      .width('100%')
      .padding({
    left: 16, right: 16, bottom: 8 })

      // 免费好书横向滚动列表
      Scroll(ScrollDirection.Horizontal) {
   
        Row() {
   
          ForEach(this.getFreeBooks(), (book: BookType) => {
   
            this.FreeBookCard(book)
          })
        }
        .padding({
    left: 16, right: 16 })
      }
      .scrollBar(BarState.Off)
      .width('100%')
      .margin({
    bottom: 16 })

      // 全部书籍标题
      Row() {
   
        Text('全部书籍')
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor('#333333')

        Blank()

        Text('查看更多 >')
          .fontSize(14)
          .fontColor('#673AB7')
      }
      .width('100%')
      .padding({
    left: 16, right: 16, bottom: 8 })

      // 使用GridRow和GridCol实现网格布局
      GridRow({
   
        columns: {
    xs: 2, sm: 3, md: 4, lg: 5 },
        gutter: {
    x: 16, y: 16 }
      }) {
   
        ForEach(this.books, (book: BookType) => {
   
          GridCol() {
   
            this.BookCard(book)
          }
        })
      }
      .width('100%')
      .padding(16)
    }
    .width('100%')
  }
  .scrollBar(BarState.Off)
  .scrollable(ScrollDirection.Vertical)
  .width('100%')
  .layoutWeight(1)
}

4.5 电子书卡片实现

// 新书卡片
@Builder
private NewBookCard(book: BookType) {
   
  Column() {
   
    // 书籍封面
    Stack() {
   
      Image(book.cover)
        .width(120)
        .height(160)
        .borderRadius(8)
        .objectFit(ImageFit.Cover)

      // 新书标签
      Text('新书')
        .fontSize(12)
        .fontColor(Color.White)
        .backgroundColor('#FF4081')
        .borderRadius(4)
        .padding({
    left: 6, right: 6, top: 2, bottom: 2 })
        .position({
    x: 8, y: 8 })
    }
    .width(120)
    .height(160)

    // 书名
    Text(book.title)
      .fontSize(14)
      .fontWeight(FontWeight.Medium)
      .fontColor('#333333')
      .maxLines(1)
      .textOverflow({
    overflow: TextOverflow.Ellipsis })
      .width(120)
      .margin({
    top: 8 })

    // 作者
    Text(book.author)
      .fontSize(12)
      .fontColor('#666666')
      .maxLines(1)
      .textOverflow({
    overflow: TextOverflow.Ellipsis })
      .width(120)
      .margin({
    top: 4 })
  }
  .margin({
    right: 12 })
}

// 免费书籍卡片
@Builder
private FreeBookCard(book: BookType) {
   
  Column() {
   
    // 书籍封面
    Stack() {
   
      Image(book.cover)
        .width(120)
        .height(160)
        .borderRadius(8)
        .objectFit(ImageFit.Cover)

      // 免费标签
      Text('免费')
        .fontSize(12)
        .fontColor(Color.White)
        .backgroundColor('#4CAF50')
        .borderRadius(4)
        .padding({
    left: 6, right: 6, top: 2, bottom: 2 })
        .position({
    x: 8, y: 8 })
    }
    .width(120)
    .height(160)

    // 书名
    Text(book.title)
      .fontSize(14)
      .fontWeight(FontWeight.Medium)
      .fontColor('#333333')
      .maxLines(1)
      .textOverflow({
    overflow: TextOverflow.Ellipsis })
      .width(120)
      .margin({
    top: 8 })

    // 作者
    Text(book.author)
      .fontSize(12)
      .fontColor('#666666')
      .maxLines(1)
      .textOverflow({
    overflow: TextOverflow.Ellipsis })
      .width(120)
      .margin({
    top: 4 })
  }
  .margin({
    right: 12 })
}

// 标准书籍卡片
@Builder
private BookCard(book: BookType) {
   
  Column() {
   
    // 书籍封面
    Stack() {
   
      Image(book.cover)
        .width('100%')
        .aspectRatio(0.75) // 3:4的宽高比
        .borderRadius(8)
        .objectFit(ImageFit.Cover)

      // 免费或新书标签
      if (book.isFree) {
   
        Text('免费')
          .fontSize(12)
          .fontColor(Color.White)
          .backgroundColor('#4CAF50')
          .borderRadius(4)
          .padding({
    left: 6, right: 6, top: 2, bottom: 2 })
          .position({
    x: 8, y: 8 })
      } else if (book.isNew) {
   
        Text('新书')
          .fontSize(12)
          .fontColor(Color.White)
          .backgroundColor('#FF4081')
          .borderRadius(4)
          .padding({
    left: 6, right: 6, top: 2, bottom: 2 })
          .position({
    x: 8, y: 8 })
      }
    }
    .width('100%')

    // 书名
    Text(book.title)
      .fontSize(14)
      .fontWeight(FontWeight.Medium)
      .fontColor('#333333')
      .maxLines(1)
      .textOverflow({
    overflow: TextOverflow.Ellipsis })
      .width('100%')
      .margin({
    top: 8 })

    // 作者
    Text(book.author)
      .fontSize(12)
      .fontColor('#666666')
      .maxLines(1)
      .textOverflow({
    overflow: TextOverflow.Ellipsis })
      .width('100%')
      .margin({
    top: 4 })

    // 评分和价格
    Row() {
   
      Row() {
   
        Image($r('app.media.ic_star'))
          .width(12)
          .height(12)
          .margin({
    right: 4 })

        Text(book.rating.toString())
          .fontSize(12)
          .fontColor('#FFC107')
      }

      Blank()

      Text(book.isFree ? '免费' : ${
     book.price}`)
        .fontSize(12)
        .fontWeight(FontWeight.Bold)
        .fontColor(book.isFree ? '#4CAF50' : '#FF5722')
    }
    .width('100%')
    .margin({
    top: 4 })
  }
  .width('100%')
  .backgroundColor(Color.White)
  .borderRadius(8)
  .padding(8)
}

4.6 辅助方法

// 获取新书列表
private getNewBooks(): BookType[] {
   
  return this.books.filter(book => book.isNew);
}

// 获取免费书籍列表
private getFreeBooks(): BookType[] {
   
  return this.books.filter(book => book.isFree);
}

5. GridRow和GridCol配置详解

在本案例中,我们使用了GridRow和GridCol组件实现网格布局。下面详细解析其配置:

5.1 GridRow配置

GridRow({
   
  columns: {
    xs: 2, sm: 3, md: 4, lg: 5 },
  gutter: {
    x: 16, y: 16 }
})
  • columns:定义不同屏幕尺寸下的列数

    • xs: 2:极小屏幕(如小型手机)显示2列
    • sm: 3:小屏幕(如大型手机)显示3列
    • md: 4:中等屏幕(如平板)显示4列
    • lg: 5:大屏幕(如桌面)显示5列
  • gutter:定义网格间的间距

    • x: 16:水平间距为16像素
    • y: 16:垂直间距为16像素

5.2 GridCol配置

在本案例中,我们使用了默认的GridCol配置,没有指定span属性,这意味着每个电子书卡片占据一个网格单元。

GridCol() {
   
  this.BookCard(book)
}

如果需要某些电子书卡片占据更多的空间,可以通过span属性进行配置:

GridCol({
   
  span: {
    xs: 2, sm: 1, md: 1, lg: 1 }
}) {
   
  this.BookCard(book)
}

这样配置后,在极小屏幕(xs)上,该电子书卡片会占据2列,而在其他屏幕尺寸上占据1列。

6. 布局效果分析

6.1 响应式布局

通过GridRow的columns配置,我们实现了响应式布局,使应用能够适应不同屏幕尺寸的设备:

屏幕尺寸 列数 效果
极小屏幕(xs) 2列 每行显示2个电子书卡片
小屏幕(sm) 3列 每行显示3个电子书卡片
中等屏幕(md) 4列 每行显示4个电子书卡片
大屏幕(lg) 5列 每行显示5个电子书卡片

6.2 网格间距

通过GridRow的gutter配置,我们设置了网格间的间距为16像素,使布局更加美观、清晰。

6.3 电子书卡片设计

我们设计了三种电子书卡片:

  1. 新书卡片:用于横向滚动的新书上架区域

    • 固定宽度为120像素
    • 显示新书标签
    • 显示书名和作者
  2. 免费书籍卡片:用于横向滚动的免费好书区域

    • 固定宽度为120像素
    • 显示免费标签
    • 显示书名和作者
  3. 标准书籍卡片:用于网格布局的全部书籍区域

    • 宽度自适应
    • 根据书籍属性显示新书或免费标签
    • 显示书名、作者、评分和价格

这种设计使用户能够快速获取电子书的关键信息,便于做出选择。

7. GridRow和GridCol组件详解

7.1 GridRow组件

GridRow是HarmonyOS NEXT提供的网格行容器组件,用于创建网格布局。它具有以下主要属性:

属性 类型 描述
columns number \ { xs?: number, sm?: number, md?: number, lg?: number, xl?: number, xxl?: number } 当前行的总列数
gutter number \ { x?: number, y?: number } 栅格间隔
breakpoints { value: number, reference: BreakpointsReference }[] 自定义断点值

7.2 GridCol组件

GridCol是HarmonyOS NEXT提供的网格列容器组件,用于在GridRow中创建网格列。它具有以下主要属性:

属性 类型 描述
span number \ { xs?: number, sm?: number, md?: number, lg?: number, xl?: number, xxl?: number } 列宽度
offset number \ { xs?: number, sm?: number, md?: number, lg?: number, xl?: number, xxl?: number } 列偏移量
order number \ { xs?: number, sm?: number, md?: number, lg?: number, xl?: number, xxl?: number } 列顺序

8. 完整代码

@Entry
@Component
struct EBookGrid {
   
  // 电子书数据类型
  interface BookType {
   
    id: number;         // 书籍ID
    title: string;      // 书名
    cover: Resource;    // 封面图片
    author: string;     // 作者
    category: string;   // 分类
    rating: number;     // 评分
    price: number;      // 价格
    isFree: boolean;    // 是否免费
    isNew: boolean;     // 是否新书
    description: string; // 简介
  }

  // 电子书数据
  private books: BookType[] = [
    {
   
      id: 1,
      title: '人工智能导论',
      cover: $r('app.media.book_ai'),
      author: '李明',
      category: '计算机',
      rating: 4.8,
      price: 68,
      isFree: false,
      isNew: true,
      description: '本书全面介绍了人工智能的基本概念、发展历史、核心技术和应用领域,适合人工智能初学者阅读。'
    },
    {
   
      id: 2,
      title: '数据结构与算法',
      cover: $r('app.media.book_algorithm'),
      author: '张伟',
      category: '计算机',
      rating: 4.9,
      price: 78,
      isFree: false,
      isNew: false,
      description: '本书详细讲解了常用的数据结构和算法,包括数组、链表、栈、队列、树、图、排序和搜索算法等。'
    },
    {
   
      id: 3,
      title: '深度学习实战',
      cover: $r('app.media.book_deep_learning'),
      author: '王芳',
      category: '计算机',
      rating: 4.7,
      price: 88,
      isFree: false,
      isNew: true,
      description: '本书通过实际案例讲解深度学习的原理和应用,包括神经网络、卷积神经网络、循环神经网络等。'
    },
    {
   
      id: 4,
      title: '经济学原理',
      cover: $r('app.media.book_economics'),
      author: '刘强',
      category: '经济',
      rating: 4.6,
      price: 0,
      isFree: true,
      isNew: false,
      description: '本书介绍了经济学的基本原理和概念,包括供需关系、市场结构、宏观经济政策等。'
    },
    {
   
      id: 5,
      title: '心理学入门',
      cover: $r('app.media.book_psychology'),
      author: '陈静',
      category: '心理',
      rating: 4.5,
      price: 58,
      isFree: false,
      isNew: false,
      description: '本书介绍了心理学的基本理论和研究方法,包括认知心理学、发展心理学、社会心理学等。'
    },
    {
   
      id: 6,
      title: '现代文学赏析',
      cover: $r('app.media.book_literature'),
      author: '赵红',
      category: '文学',
      rating: 4.4,
      price: 0,
      isFree: true,
      isNew: false,
      description: '本书精选了现代文学作品进行赏析,包括小说、诗歌、散文等多种体裁。'
    },
    {
   
      id: 7,
      title: '健康生活指南',
      cover: $r('app.media.book_health'),
      author: '孙健',
      category: '健康',
      rating: 4.3,
      price: 48,
      isFree: false,
      isNew: true,
      description: '本书提供了健康生活的指导和建议,包括饮食、运动、心理健康等方面。'
    },
    {
   
      id: 8,
      title: '旅行摄影技巧',
      cover: $r('app.media.book_photography'),
      author: '吴光',
      category: '摄影',
      rating: 4.7,
      price: 68,
      isFree: false,
      isNew: false,
      description: '本书介绍了旅行摄影的技巧和方法,包括构图、光线、后期处理等方面。'
    },
    {
   
      id: 9,
      title: '烹饪艺术',
      cover: $r('app.media.book_cooking'),
      author: '郑厨',
      category: '美食',
      rating: 4.8,
      price: 0,
      isFree: true,
      isNew: true,
      description: '本书介绍了烹饪的基本技巧和方法,包括中餐、西餐、甜点等多种菜系。'
    },
    {
   
      id: 10,
      title: '投资理财基础',
      cover: $r('app.media.book_finance'),
      author: '黄金',
      category: '金融',
      rating: 4.5,
      price: 58,
      isFree: false,
      isNew: false,
      description: '本书介绍了投资理财的基本知识和方法,包括股票、基金、债券等投资工具。'
    }
  ];

  @State currentCategory: string = '推荐';
  private categories: string[] = ['推荐', '计算机', '经济', '文学', '心理', '健康', '摄影', '美食', '金融'];

  build() {
   
    Column() {
   
      // 顶部搜索栏
      this.SearchBar()

      // 分类标签栏
      this.CategoryTabs()

      // 电子书网格列表
      this.BookGrid()
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }

  @Builder
  private SearchBar() {
   
    Row() {
   
      // 搜索框
      Row() {
   
        Image($r('app.media.ic_search'))
          .width(20)
          .height(20)
          .margin({
    right: 8 })

        TextInput({
    placeholder: '搜索书名、作者' })
          .layoutWeight(1)
          .backgroundColor('transparent')
          .placeholderColor('#999999')
          .fontSize(14)
          .height('100%')
      }
      .width('85%')
      .height(40)
      .backgroundColor(Color.White)
      .borderRadius(20)
      .padding({
    left: 12, right: 12 })

      // 筛选按钮
      Image($r('app.media.ic_filter'))
        .width(24)
        .height(24)
        .margin({
    left: 12 })
    }
    .width('100%')
    .padding({
    left: 16, right: 16, top: 12, bottom: 12 })
    .backgroundColor('#673AB7')
  }

  @Builder
  private CategoryTabs() {
   
    Scroll(ScrollDirection.Horizontal) {
   
      Row() {
   
        ForEach(this.categories, (category: string) => {
   
          Text(category)
            .fontSize(14)
            .fontColor(this.currentCategory === category ? '#673AB7' : '#666666')
            .fontWeight(this.currentCategory === category ? FontWeight.Bold : FontWeight.Normal)
            .padding({
    left: 16, right: 16, top: 12, bottom: 12 })
            .backgroundColor(this.currentCategory === category ? '#EDE7F6' : 'transparent')
            .borderRadius(16)
            .margin({
    right: 8 })
            .onClick(() => {
   
              this.currentCategory = category;
            })
        })
      }
      .padding({
    left: 16, right: 16 })
    }
    .scrollBar(BarState.Off)
    .width('100%')
  }

  @Builder
  private BookGrid() {
   
    Scroll() {
   
      Column() {
   
        // 新书上架标题
        Row() {
   
          Text('新书上架')
            .fontSize(18)
            .fontWeight(FontWeight.Bold)
            .fontColor('#333333')

          Blank()

          Text('查看更多 >')
            .fontSize(14)
            .fontColor('#673AB7')
        }
        .width('100%')
        .padding({
    left: 16, right: 16, top: 16, bottom: 8 })

        // 新书上架横向滚动列表
        Scroll(ScrollDirection.Horizontal) {
   
          Row() {
   
            ForEach(this.getNewBooks(), (book: BookType) => {
   
              this.NewBookCard(book)
            })
          }
          .padding({
    left: 16, right: 16 })
        }
        .scrollBar(BarState.Off)
        .width('100%')
        .margin({
    bottom: 16 })

        // 免费好书标题
        Row() {
   
          Text('免费好书')
            .fontSize(18)
            .fontWeight(FontWeight.Bold)
            .fontColor('#333333')

          Blank()

          Text('查看更多 >')
            .fontSize(14)
            .fontColor('#673AB7')
        }
        .width('100%')
        .padding({
    left: 16, right: 16, bottom: 8 })

        // 免费好书横向滚动列表
        Scroll(ScrollDirection.Horizontal) {
   
          Row() {
   
            ForEach(this.getFreeBooks(), (book: BookType) => {
   
              this.FreeBookCard(book)
            })
          }
          .padding({
    left: 16, right: 16 })
        }
        .scrollBar(BarState.Off)
        .width('100%')
        .margin({
    bottom: 16 })

        // 全部书籍标题
        Row() {
   
          Text('全部书籍')
            .fontSize(18)
            .fontWeight(FontWeight.Bold)
            .fontColor('#333333')

          Blank()

          Text('查看更多 >')
            .fontSize(14)
            .fontColor('#673AB7')
        }
        .width('100%')
        .padding({
    left: 16, right: 16, bottom: 8 })

        // 使用GridRow和GridCol实现网格布局
        GridRow({
   
          columns: {
    xs: 2, sm: 3, md: 4, lg: 5 },
          gutter: {
    x: 16, y: 16 }
        }) {
   
          ForEach(this.books, (book: BookType) => {
   
            GridCol() {
   
              this.BookCard(book)
            }
          })
        }
        .width('100%')
        .padding(16)
      }
      .width('100%')
    }
    .scrollBar(BarState.Off)
    .scrollable(ScrollDirection.Vertical)
    .width('100%')
    .layoutWeight(1)
  }

  // 新书卡片
  @Builder
  private NewBookCard(book: BookType) {
   
    Column() {
   
      // 书籍封面
      Stack() {
   
        Image(book.cover)
          .width(120)
          .height(160)
          .borderRadius(8)
          .objectFit(ImageFit.Cover)

        // 新书标签
        Text('新书')
          .fontSize(12)
          .fontColor(Color.White)
          .backgroundColor('#FF4081')
          .borderRadius(4)
          .padding({
    left: 6, right: 6, top: 2, bottom: 2 })
          .position({
    x: 8, y: 8 })
      }
      .width(120)
      .height(160)

      // 书名
      Text(book.title)
        .fontSize(14)
        .fontWeight(FontWeight.Medium)
        .fontColor('#333333')
        .maxLines(1)
        .textOverflow({
    overflow: TextOverflow.Ellipsis })
        .width(120)
        .margin({
    top: 8 })

      // 作者
      Text(book.author)
        .fontSize(12)
        .fontColor('#666666')
        .maxLines(1)
        .textOverflow({
    overflow: TextOverflow.Ellipsis })
        .width(120)
        .margin({
    top: 4 })
    }
    .margin({
    right: 12 })
  }

  // 免费书籍卡片
  @Builder
  private FreeBookCard(book: BookType) {
   
    Column() {
   
      // 书籍封面
      Stack() {
   
        Image(book.cover)
          .width(120)
          .height(160)
          .borderRadius(8)
          .objectFit(ImageFit.Cover)

        // 免费标签
        Text('免费')
          .fontSize(12)
          .fontColor(Color.White)
          .backgroundColor('#4CAF50')
          .borderRadius(4)
          .padding({
    left: 6, right: 6, top: 2, bottom: 2 })
          .position({
    x: 8, y: 8 })
      }
      .width(120)
      .height(160)

      // 书名
      Text(book.title)
        .fontSize(14)
        .fontWeight(FontWeight.Medium)
        .fontColor('#333333')
        .maxLines(1)
        .textOverflow({
    overflow: TextOverflow.Ellipsis })
        .width(120)
        .margin({
    top: 8 })

      // 作者
      Text(book.author)
        .fontSize(12)
        .fontColor('#666666')
        .maxLines(1)
        .textOverflow({
    overflow: TextOverflow.Ellipsis })
        .width(120)
        .margin({
    top: 4 })
    }
    .margin({
    right: 12 })
  }

  // 标准书籍卡片
  @Builder
  private BookCard(book: BookType) {
   
    Column() {
   
      // 书籍封面
      Stack() {
   
        Image(book.cover)
          .width('100%')
          .aspectRatio(0.75) // 3:4的宽高比
          .borderRadius(8)
          .objectFit(ImageFit.Cover)

        // 免费或新书标签
        if (book.isFree) {
   
          Text('免费')
            .fontSize(12)
            .fontColor(Color.White)
            .backgroundColor('#4CAF50')
            .borderRadius(4)
            .padding({
    left: 6, right: 6, top: 2, bottom: 2 })
            .position({
    x: 8, y: 8 })
        } else if (book.isNew) {
   
          Text('新书')
            .fontSize(12)
            .fontColor(Color.White)
            .backgroundColor('#FF4081')
            .borderRadius(4)
            .padding({
    left: 6, right: 6, top: 2, bottom: 2 })
            .position({
    x: 8, y: 8 })
        }
      }
      .width('100%')

      // 书名
      Text(book.title)
        .fontSize(14)
        .fontWeight(FontWeight.Medium)
        .fontColor('#333333')
        .maxLines(1)
        .textOverflow({
    overflow: TextOverflow.Ellipsis })
        .width('100%')
        .margin({
    top: 8 })

      // 作者
      Text(book.author)
        .fontSize(12)
        .fontColor('#666666')
        .maxLines(1)
        .textOverflow({
    overflow: TextOverflow.Ellipsis })
        .width('100%')
        .margin({
    top: 4 })

      // 评分和价格
      Row() {
   
        Row() {
   
          Image($r('app.media.ic_star'))
            .width(12)
            .height(12)
            .margin({
    right: 4 })

          Text(book.rating.toString())
            .fontSize(12)
            .fontColor('#FFC107')
        }

        Blank()

        Text(book.isFree ? '免费' : ${
     book.price}`)
          .fontSize(12)
          .fontWeight(FontWeight.Bold)
          .fontColor(book.isFree ? '#4CAF50' : '#FF5722')
      }
      .width('100%')
      .margin({
    top: 4 })
    }
    .width('100%')
    .backgroundColor(Color.White)
    .borderRadius(8)
    .padding(8)
  }

  // 获取新书列表
  private getNewBooks(): BookType[] {
   
    return this.books.filter(book => book.isNew);
  }

  // 获取免费书籍列表
  private getFreeBooks(): BookType[] {
   
    return this.books.filter(book => book.isFree);
  }
}

9. 总结

本教程详细讲解了如何使用HarmonyOS NEXT中的GridRow和GridCol组件实现电子书网格布局。通过合理的数据结构设计、精心的UI设计和灵活的GridRow配置,我们实现了一个美观、响应式的电子书展示页面。

主要内容包括:

  • 电子书数据结构设计和数据准备
  • 整体布局实现,包括顶部搜索栏、分类标签栏和电子书网格列表
  • GridRow和GridCol组件的配置和使用
  • 电子书卡片的设计和实现,包括新书卡片、免费书籍卡片和标准书籍卡片
  • 布局效果分析
相关文章
|
3月前
|
容器
HarmonyOS NEXT仓颉开发语言实战案例:外卖App
仓颉语言实战分享,教你如何用仓颉开发外卖App界面。内容包括页面布局、导航栏自定义、搜索框实现、列表模块构建等,附完整代码示例。轻松掌握Scroll、List等组件使用技巧,提升HarmonyOS应用开发能力。
|
2月前
|
移动开发 前端开发 JavaScript
鸿蒙NEXT时代你所不知道的全平台跨端框架:CMP、Kuikly、Lynx、uni-app x等
本篇基于当前各大活跃的跨端框架的现状,对比当前它们的情况和未来的可能,帮助你在选择框架时更好理解它们的特点和差异。
286 0
|
3月前
|
安全 API 开发工具
【HarmonyOS NEXT】一键扫码功能
这些Kit为我们应用开发提升了极大地效率。很多简单的功能,如果不需要太深的定制化需求,直接调用kit提供的API就可以实现,在android或者ios上需要很多代码才能实现的功能效果。
109 0
HarmonyOS NEXT仓颉开发语言实战案例:电影App
周末好!本文分享使用仓颉语言重构ArkTS实现的电影App案例,对比两者在UI布局、组件写法及语法差异。内容包括页面结构、列表分组、分类切换与电影展示等。通过代码演示仓颉在HarmonyOS开发中的应用。##仓颉##ArkTS##HarmonyOS开发
|
3月前
|
容器
HarmonyOS NEXT仓颉开发语言实战案例:健身App
本期分享一个健身App首页的布局实现,顶部采用Stack容器实现重叠背景与偏移效果,列表部分使用List结合Scroll实现可滚动内容。代码结构清晰,适合学习HarmonyOS布局技巧。
HarmonyOS NEXT仓颉开发语言实战案例:小而美的旅行App
本文分享了一个旅行App首页的设计与实现,使用List容器搭配Row、Column布局完成个人信息、功能列表及推荐模块的排版,详细展示了HarmonyOS下的界面构建技巧。
|
10天前
|
存储 缓存 5G
鸿蒙 HarmonyOS NEXT端云一体化开发-云存储篇
本文介绍用户登录后获取昵称、头像的方法,包括通过云端API和AppStorage两种方式,并实现上传头像至云存储及更新用户信息。同时解决图片缓存问题,添加上传进度提示,支持自动登录判断,提升用户体验。
59 0
|
10天前
|
存储 负载均衡 数据库
鸿蒙 HarmonyOS NEXT端云一体化开发-云函数篇
本文介绍基于华为AGC的端云一体化开发流程,涵盖项目创建、云函数开通、应用配置及DevEco集成。重点讲解云函数的编写、部署、调用与传参,并涉及环境变量设置、负载均衡、重试机制与熔断策略等高阶特性,助力开发者高效构建稳定云端服务。
87 0
鸿蒙 HarmonyOS NEXT端云一体化开发-云函数篇
|
10天前
|
存储 JSON 数据建模
鸿蒙 HarmonyOS NEXT端云一体化开发-云数据库篇
云数据库采用存储区、对象类型、对象三级结构,支持灵活的数据建模与权限管理,可通过AGC平台或本地项目初始化,实现数据的增删改查及端侧高效调用。
37 0
|
10天前
|
存储 开发者 容器
鸿蒙 HarmonyOS NEXT星河版APP应用开发-ArkTS面向对象及组件化UI开发使用实例
本文介绍了ArkTS语言中的Class类、泛型、接口、模块化、自定义组件及状态管理等核心概念,并结合代码示例讲解了对象属性、构造方法、继承、静态成员、访问修饰符等内容,同时涵盖了路由管理、生命周期和Stage模型等应用开发关键知识点。
96 0
鸿蒙 HarmonyOS NEXT星河版APP应用开发-ArkTS面向对象及组件化UI开发使用实例