137.[HarmonyOS NEXT 实战案例七:List系列] 多列列表组件实战:打造精美应用推荐页 基础篇

2025-06-30 22:14:44
105次阅读
0个评论

[HarmonyOS NEXT 实战案例七:List系列] 多列列表组件实战:打造精美应用推荐页 基础篇

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

效果演示

image.png

一、多列列表基础介绍

在HarmonyOS NEXT应用开发中,多列列表是一种常见的UI布局方式,特别适合展示网格状的内容,如应用商店、图片库、商品展示等。多列列表可以在有限的屏幕空间内高效地展示更多内容,提升用户体验。

1.1 多列列表的特点

特点 说明
网格布局 内容以网格形式排列,可同时展示多个列表项
高效利用空间 在同一屏幕空间内可展示更多内容
灵活的列数设置 可根据屏幕大小和内容特点设置不同的列数
支持分割线 可添加网格分割线,使界面更加清晰
自适应布局 可根据屏幕方向和大小自动调整布局

1.2 多列列表的实现方式

在HarmonyOS NEXT中,实现多列列表主要有两种方式:

  1. 使用List组件的lanes属性:通过设置List组件的lanes属性,可以将列表项排列为多列布局。
  2. 使用Grid组件:Grid组件专门用于创建网格布局,适合更复杂的网格需求。

在本教程中,我们将重点介绍使用List组件的lanes属性实现多列列表。

二、多列列表实战案例

在本案例中,我们将实现一个应用推荐页面,以多列网格的形式展示应用信息,包括应用图标、名称和下载量。

2.1 数据模型定义

首先,我们需要定义应用的数据模型:

interface AppType {
    name: string;
    icon: Resource;
    downloads: string;
}

这个接口定义了应用的三个属性:名称、图标和下载量。其中图标使用Resource类型,表示资源引用。

2.2 数据准备

接下来,我们准备应用数据:

private apps: AppType[] = [
    { name: '音乐播放器', icon: $r("app.media.music_icon"), downloads: '1000万+' },
    { name: '视频播放器', icon: $r('app.media.video_icon_videos'), downloads: '500万+' },
    { name: '图片编辑器', icon: $r('app.media.photo_icon'), downloads: '300万+' },
    { name: '日历', icon: $r('app.media.calendar'), downloads: '800万+' },
    { name: '天气', icon: $r('app.media.active_weather_icon'), downloads: '1200万+' },
    { name: '计算器', icon: $r('app.media.mobile_calculator_ap'), downloads: '600万+' },
    { name: '备忘录', icon: $r("app.media.note_icon"), downloads: '400万+' },
    { name: '地图', icon: $r('app.media.map_icon2'), downloads: '900万+' },
    { name: '电子书', icon: $r("app.media.Facebook_icon_03"), downloads: '200万+' },
    { name: '购物', icon: $r('app.media.Shopping_icon'), downloads: '700万+' },
    { name: '游戏中心', icon: $r("app.media.game_icon"), downloads: '1500万+' },
    { name: '健康', icon: $r("app.media.dcc_health_icon"), downloads: '350万+' },
]

我们创建了一个包含12个应用的数组,每个应用都有名称、图标资源和下载量信息。

2.3 页面结构设计

整个页面采用垂直布局,包含标题栏、应用列表和底部导航栏三部分:

build() {
    Column() {
        // 标题栏
        Row() {
            Text('应用推荐')
                .fontSize(24)
                .fontWeight(FontWeight.Bold)
        }
        .width('100%')
        .height(56)
        .padding({ left: 16 })
        .backgroundColor('#F1F3F5')

        // 多列应用列表
        List() {
            // 列表内容
        }
        .width('100%')
        .layoutWeight(1)
        .lanes(3) // 设置为3列布局
        .divider({ // 设置网格分割线
            strokeWidth: 1,
            color: '#E5E5E5',
            startMargin: 8,
            endMargin: 8
        })

        // 底部导航栏
        Row() {
            // 导航栏内容
        }
        .width('100%')
        .height(60)
        .padding({ top: 8, bottom: 8 })
        .backgroundColor('#FFFFFF')
        .borderColor('#E5E5E5')
        .borderWidth({ top: 1 })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#FFFFFF')
}

在这个结构中:

  • 使用Column作为根容器,占满整个屏幕
  • 顶部是一个Row容器,作为标题栏,包含标题文本
  • 中间是List组件,用于显示应用列表,设置lanes(3)使其成为3列布局
  • 底部是一个Row容器,作为导航栏

2.4 列表项实现

接下来,我们实现列表项的内容:

List() {
    ForEach(this.apps, (app:AppType) => {
        ListItem() {
            Column() {
                // 应用图标
                Image(app.icon)
                    .width(60)
                    .height(60)
                    .borderRadius(12)

                // 应用名称
                Text(app.name)
                    .width(100)
                    .fontSize(14)
                    .margin({ top: 8 })
                    .maxLines(1)
                    .textOverflow({ overflow: TextOverflow.Ellipsis })

                // 下载量
                Text(app.downloads)
                    .width(100)
                    .fontSize(12)
                    .fontColor('#666666')
                    .margin({ top: 4 })
            }
            .alignItems(HorizontalAlign.Center)
            .width('100%')
            .padding(12)
        }
        .width('33%') // 每个项目占用1/3的宽度
        .padding(8)
    })
}

在这段代码中:

  1. 使用ForEach遍历apps数组,为每个应用创建一个ListItem
  2. 每个ListItem包含一个Column布局,用于垂直排列应用图标、名称和下载量
  3. 应用图标使用Image组件,设置为圆角矩形(通过borderRadius实现)
  4. 应用名称和下载量使用Text组件,设置不同的字体大小和颜色
  5. 设置ListItem的宽度为'33%',使每行显示3个应用

2.5 底部导航栏实现

最后,我们实现底部导航栏:

Row() {
    Column() {
        Image($r('app.media.01'))
            .width(24)
            .height(24)
        Text('首页')
            .fontSize(12)
            .margin({ top: 4 })
    }
    .layoutWeight(1)

    Column() {
        Image($r('app.media.02'))
            .width(24)
            .height(24)
        Text('分类')
            .fontSize(12)
            .margin({ top: 4 })
    }
    .layoutWeight(1)

    Column() {
        Image($r('app.media.03'))
            .width(24)
            .height(24)
        Text('排行')
            .fontSize(12)
            .margin({ top: 4 })
            .fontColor('#007DFF')
    }
    .layoutWeight(1)

    Column() {
        Image($r('app.media.04'))
            .width(24)
            .height(24)
        Text('我的')
            .fontSize(12)
            .margin({ top: 4 })
    }
    .layoutWeight(1)
}

在这段代码中:

  1. 使用Row作为导航栏的容器,包含4个Column子容器
  2. 每个Column代表一个导航项,包含一个图标和一个文本
  3. 使用layoutWeight(1)使4个导航项平均分配空间
  4. 为当前选中的导航项(排行)设置特殊的文本颜色

三、完整代码解析

让我们来看一下完整的代码实现:

@Component
export struct MultiColumnList {
    // 应用数据
    private apps: AppType[] = [
        { name: '音乐播放器', icon: $r("app.media.music_icon"), downloads: '1000万+' },
        { name: '视频播放器', icon: $r('app.media.video_icon_videos'), downloads: '500万+' },
        { name: '图片编辑器', icon: $r('app.media.photo_icon'), downloads: '300万+' },
        { name: '日历', icon: $r('app.media.calendar'), downloads: '800万+' },
        { name: '天气', icon: $r('app.media.active_weather_icon'), downloads: '1200万+' },
        { name: '计算器', icon: $r('app.media.mobile_calculator_ap'), downloads: '600万+' },
        { name: '备忘录', icon: $r("app.media.note_icon"), downloads: '400万+' },
        { name: '地图', icon: $r('app.media.map_icon2'), downloads: '900万+' },
        { name: '电子书', icon: $r("app.media.Facebook_icon_03"), downloads: '200万+' },
        { name: '购物', icon: $r('app.media.Shopping_icon'), downloads: '700万+' },
        { name: '游戏中心', icon: $r("app.media.game_icon"), downloads: '1500万+' },
        { name: '健康', icon: $r("app.media.dcc_health_icon"), downloads: '350万+' },
    ]

    build() {
        Column() {
            // 标题栏
            Row() {
                Text('应用推荐')
                    .fontSize(24)
                    .fontWeight(FontWeight.Bold)
            }
            .width('100%')
            .height(56)
            .padding({ left: 16 })
            .backgroundColor('#F1F3F5')

            // 多列应用列表
            List() {
                ForEach(this.apps, (app:AppType) => {
                    ListItem() {
                        Column() {
                            // 应用图标
                            Image(app.icon)
                                .width(60)
                                .height(60)
                                .borderRadius(12)

                            // 应用名称
                            Text(app.name)
                                .width(100)
                                .fontSize(14)
                                .margin({ top: 8 })
                                .maxLines(1)
                                .textOverflow({ overflow: TextOverflow.Ellipsis })

                            // 下载量
                            Text(app.downloads)
                                .width(100)
                                .fontSize(12)
                                .fontColor('#666666')
                                .margin({ top: 4 })
                        }
                        .alignItems(HorizontalAlign.Center)
                        .width('100%')
                        .padding(12)
                    }
                    .width('33%') // 每个项目占用1/3的宽度
                    .padding(8)
                })

            }
            .width('100%')
            .layoutWeight(1)
            .lanes(3) // 设置为3列布局
            .divider({ // 设置网格分割线
                strokeWidth: 1,
                color: '#E5E5E5',
                startMargin: 8,
                endMargin: 8
            })

            // 底部导航栏
            Row() {
                Column() {
                    Image($r('app.media.01'))
                        .width(24)
                        .height(24)
                    Text('首页')
                        .fontSize(12)
                        .margin({ top: 4 })
                }
                .layoutWeight(1)

                Column() {
                    Image($r('app.media.02'))
                        .width(24)
                        .height(24)
                    Text('分类')
                        .fontSize(12)
                        .margin({ top: 4 })
                }
                .layoutWeight(1)

                Column() {
                    Image($r('app.media.03'))
                        .width(24)
                        .height(24)
                    Text('排行')
                        .fontSize(12)
                        .margin({ top: 4 })
                        .fontColor('#007DFF')
                }
                .layoutWeight(1)

                Column() {
                    Image($r('app.media.04'))
                        .width(24)
                        .height(24)
                    Text('我的')
                        .fontSize(12)
                        .margin({ top: 4 })
                }
                .layoutWeight(1)
            }
            .width('100%')
            .height(60)
            .padding({ top: 8, bottom: 8 })
            .backgroundColor('#FFFFFF')
            .borderColor('#E5E5E5')
            .borderWidth({ top: 1 })
        }
        .width('100%')
        .height('100%')
        .backgroundColor('#FFFFFF')
    }
}

3.1 代码结构分析

部分 说明
@Component 组件装饰器,表明这是一个自定义组件
private apps 私有属性,存储应用数据
build() 组件的构建函数,定义组件的UI结构
Column 根容器,垂直排列子元素
Row 标题栏和底部导航栏容器,水平排列子元素
List 列表容器,用于展示应用列表
ForEach 循环构建器,遍历应用数据
ListItem 列表项容器,定义每个应用的布局

3.2 样式设置分析

在这个案例中,我们使用了多种样式设置来美化界面:

  1. 尺寸设置

    • 使用width('100%')和height('100%')使组件占满父容器
    • 使用layoutWeight(1)使List组件占据剩余空间
    • 设置具体的像素值,如height(56)、width(60)等
    • 使用width('33%')设置列表项宽度为容器的1/3
  2. 边距和填充

    • 使用padding设置内边距
    • 使用margin设置外边距
  3. 颜色和背景

    • 设置背景颜色backgroundColor
    • 设置文本颜色fontColor
    • 设置边框颜色borderColor
  4. 文本样式

    • 设置字体大小fontSize
    • 设置字体粗细fontWeight
    • 使用maxLines和textOverflow处理文本溢出
  5. 特殊效果

    • 使用borderRadius设置圆角效果
    • 使用divider设置分割线
    • 使用borderWidth设置边框宽度

3.3 多列列表关键属性

实现多列列表的关键在于以下几个属性:

  1. lanes属性

    .lanes(3) // 设置为3列布局
    

    lanes属性指定了列表的列数,在本例中设置为3,表示列表项将排列为3列。

  2. 列表项宽度

    .width('33%') // 每个项目占用1/3的宽度
    

    为了使列表项能够正确排列,需要设置每个ListItem的宽度。在3列布局中,每个列表项的宽度设置为'33%',表示占用容器宽度的1/3。

  3. 网格分割线

    .divider({ // 设置网格分割线
        strokeWidth: 1,
        color: '#E5E5E5',
        startMargin: 8,
        endMargin: 8
    })
    

    divider属性用于设置列表的分割线。在多列列表中,分割线会形成网格状,使界面更加清晰。

总结

在本篇教程中,我们学习了如何使用HarmonyOS NEXT的List组件的lanes属性创建多列列表,实现了一个应用推荐页面。我们从数据模型定义、页面结构设计、列表项实现到底部导航栏实现,全面讲解了多列列表的实现过程。

收藏00

登录 后评论。没有帐号? 注册 一个。

全栈若城

  • 0回答
  • 4粉丝
  • 0关注
相关话题