149.[HarmonyOS NEXT 实战案例十一:List系列] 下拉刷新和上拉加载更多列表组件实战:打造高效新闻应用 基础篇

2025-06-30 22:25:43
103次阅读
0个评论

[HarmonyOS NEXT 实战案例十一:List系列] 下拉刷新和上拉加载更多列表组件实战:打造高效新闻应用 基础篇

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

效果演示

image.png

一、引言

在移动应用开发中,下拉刷新和上拉加载更多是列表组件中常见且重要的交互功能。下拉刷新允许用户通过向下拉动列表来获取最新内容,而上拉加载更多则允许用户通过滚动到列表底部来加载更多历史内容。这两个功能结合使用,可以提供流畅的用户体验,特别适合新闻、社交媒体等内容持续更新的应用场景。

HarmonyOS NEXT提供了强大的List组件和Refresh容器组件,使得实现这些功能变得简单高效。本教程将详细讲解如何使用这些组件打造一个具有下拉刷新和上拉加载更多功能的新闻列表应用。

二、基础知识

2.1 相关组件介绍

在实现下拉刷新和上拉加载更多功能时,我们主要用到以下组件:

  1. List组件:用于显示一系列相同类型的子组件,支持垂直和水平方向的滚动。
  2. ListItem组件:作为List的子组件,用于定义列表项的内容和行为。
  3. Refresh组件:一个容器组件,为子组件提供下拉刷新功能。
  4. ForEach:用于遍历数据集合并生成对应的UI组件。
  5. LoadingProgress:用于显示加载状态的进度指示器。

2.2 数据模型设计

在新闻应用中,我们需要定义一个数据模型来表示新闻项:

interface NewsType {
    id: number,
    title: string,
    source: string,
    time: string,
    image?: Resource,
    isTop?: boolean
}

这个接口定义了新闻项的基本属性:

  • id:新闻的唯一标识符
  • title:新闻标题
  • source:新闻来源
  • time:发布时间
  • image:可选的新闻配图
  • isTop:是否为置顶新闻

三、状态管理

在实现下拉刷新和上拉加载更多功能时,我们需要管理以下状态:

// 新闻数据
@State newsList: NewsType[] = [...]

// 是否正在刷新
@State isRefreshing: boolean = false

// 是否正在加载更多
@State isLoadingMore: boolean = false

// 是否还有更多数据
@State hasMoreData: boolean = true

// 当前页码
@State currentPage: number = 1

这些状态变量用于:

  • 跟踪当前的新闻列表数据
  • 控制刷新和加载更多的UI状态
  • 判断是否还有更多数据可加载
  • 记录当前的页码,用于分页加载

四、核心功能实现

4.1 下拉刷新功能

下拉刷新功能主要通过Refresh组件和onRefresh方法实现:

onRefresh() {
    this.isRefreshing = true
    // 模拟网络请求延迟
    setTimeout(() => {
        // 生成新的置顶新闻
        const newTopNews: NewsType = {
            id: 100 + this.newsList.length,
            title: `最新突发新闻:鸿蒙OS新功能发布 ${new Date().toLocaleTimeString()}`,
            source: '科技前沿',
            time: '刚刚',
            image: $r('app.media.big19'),
            isTop: true
        }

        // 将原有置顶新闻取消置顶
        const updatedList = this.newsList.map(item => {
            if (item.isTop) {
                item.isTop = false
            }
            return item
        })

        // 添加新的置顶新闻到列表顶部
        this.newsList = [newTopNews, ...updatedList]
        this.isRefreshing = false
        this.currentPage = 1
        this.hasMoreData = true
    }, 2000)
}

这个方法的主要步骤是:

  1. 设置刷新状态为true
  2. 模拟网络请求(实际应用中应该是真实的API调用)
  3. 创建新的置顶新闻
  4. 更新现有新闻的置顶状态
  5. 将新闻添加到列表顶部
  6. 重置刷新状态和分页相关变量

4.2 上拉加载更多功能

上拉加载更多功能主要通过ListItemonAppear事件和loadMore方法实现:

loadMore() {
    if (this.isLoadingMore || !this.hasMoreData) {
        return
    }

    this.isLoadingMore = true
    // 模拟网络请求延迟
    setTimeout(() => {
        // 模拟加载更多数据
        const moreNews: NewsType[] = [
            {
                id: 200 + this.newsList.length,
                title: `经济发展新动向:数字经济成为增长新引擎 ${this.currentPage + 1}`,
                source: '经济观察',
                time: '8小时前',
                image: this.currentPage % 2 === 0 ? $r('app.media.phone') : undefined
            },
            // 更多新闻项...
        ]

        this.newsList = [...this.newsList, ...moreNews]
        this.isLoadingMore = false
        this.currentPage++

        // 模拟数据加载完毕
        if (this.currentPage >= 4) {
            this.hasMoreData = false
        }
    }, 1500)
}

这个方法的主要步骤是:

  1. 检查是否已经在加载或没有更多数据
  2. 设置加载状态为true
  3. 模拟网络请求(实际应用中应该是真实的API调用)
  4. 创建新的新闻项
  5. 将新闻添加到列表底部
  6. 更新加载状态和页码
  7. 判断是否还有更多数据

4.3 自定义刷新头部和加载尾部

为了提供更好的用户体验,我们可以自定义刷新头部和加载尾部:

// 构建下拉刷新头部
@Builder
RefreshHeader() {
    Row() {
        if (this.isRefreshing) {
            LoadingProgress()
                .width(24)
                .height(24)
                .margin({ right: 8 })
        } else {
            Image($r('app.media.arrowright'))
                .width(24)
                .height(24)
                .margin({ right: 8 })
        }

        Text(this.isRefreshing ? '正在刷新...' : '下拉刷新')
            .fontSize(14)
            .fontColor('#666666')
    }
    .width('100%')
    .height(60)
    .justifyContent(FlexAlign.Center)
}

// 构建加载更多尾部
@Builder
LoadMoreFooter() {
    Row() {
        if (this.isLoadingMore) {
            LoadingProgress()
                .width(24)
                .height(24)
                .margin({ right: 8 })

            Text('正在加载更多...')
                .fontSize(14)
                .fontColor('#666666')
        } else if (!this.hasMoreData) {
            Text('没有更多内容了')
                .fontSize(14)
                .fontColor('#999999')
        } else {
            Text('上拉加载更多')
                .fontSize(14)
                .fontColor('#666666')
        }
    }
    .width('100%')
    .height(60)
    .justifyContent(FlexAlign.Center)
}

这两个Builder方法分别定义了:

  • 刷新头部:根据刷新状态显示不同的图标和文本
  • 加载尾部:根据加载状态和是否有更多数据显示不同的内容

五、UI构建

5.1 整体页面结构

整个页面采用垂直布局,包含标题栏和新闻列表两部分:

build() {
    Column() {
        // 标题栏
        Row() {
            Text('新闻')
                .fontSize(24)
                .fontWeight(FontWeight.Bold)

            Blank()

            Image($r('app.media.01'))
                .width(24)
                .height(24)
                .margin({ right: 16 })
        }
        .width('100%')
        .height(56)
        .padding({ left: 16, right: 16 })
        .backgroundColor('#F1F3F5')

        // 新闻列表
        Refresh({
            refreshing: $$this.isRefreshing,
            offset: 60,
            friction: 66
        }) {
            // 列表内容
        }
        .onRefreshing(() => {
            this.onRefresh()
        })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#FFFFFF')
}

5.2 新闻列表实现

在Refresh组件内部,我们使用List组件来显示新闻列表:

List() {
    // 下拉刷新头部
    ListItem() {
        this.RefreshHeader()
    }

    // 新闻列表项
    ForEach(this.newsList, (news:NewsType) => {
        ListItem() {
            Row() {
                // 新闻内容
                Column() {
                    if (news.isTop) {
                        Text('置顶')
                            .fontSize(12)
                            .fontColor('#FF3B30')
                            .backgroundColor('#FFEBEB')
                            .borderRadius(4)
                            .padding({ left: 6, right: 6, top: 2, bottom: 2 })
                            .margin({ bottom: 4 })
                    }

                    Text(news.title)
                        .fontSize(16)
                        .fontWeight(FontWeight.Medium)
                        .maxLines(2)
                        .textOverflow({ overflow: TextOverflow.Ellipsis })

                    Row() {
                        Text(news.source)
                            .fontSize(14)
                            .fontColor('#666666')

                        Text(news.time)
                            .fontSize(14)
                            .fontColor('#666666')
                            .margin({ left: 16 })
                    }
                    .margin({ top: 8 })
                }
                .alignItems(HorizontalAlign.Start)
                .layoutWeight(news.image ? 2 : 1)

                // 新闻图片(如果有)
                if (news.image) {
                    Image(news.image)
                        .width(100)
                        .height(70)
                        .borderRadius(8)
                        .margin({ left: 16 })
                        .objectFit(ImageFit.Cover)
                }
            }
            .width('100%')
            .padding({ left: 16, right: 16, top: 12, bottom: 12 })
        }
        .height(news.image ? 94 : 84)
        .backgroundColor(news.isTop ? '#FFFBF0' : '#FFFFFF')
    })

    // 加载更多尾部
    ListItem() {
        this.LoadMoreFooter()
    }
    .onAppear(() => {
        // 当滚动到底部时触发加载更多
        if (!this.isRefreshing && !this.isLoadingMore && this.hasMoreData) {
            this.loadMore()
        }
    })
}
.width('100%')
.layoutWeight(1)
.divider({ // 设置分割线
    strokeWidth: 1,
    color: '#E5E5E5',
    startMargin: 16,
    endMargin: 16
})

这段代码的主要部分是:

  1. 添加自定义的刷新头部
  2. 使用ForEach遍历新闻列表,为每个新闻项创建一个ListItem
  3. 在ListItem中根据新闻是否有图片和是否置顶来调整布局和样式
  4. 添加自定义的加载尾部,并通过onAppear事件触发加载更多功能

六、关键技术点分析

6.1 Refresh组件的使用

Refresh组件是实现下拉刷新功能的核心,它的主要属性和事件包括:

  • refreshing:控制刷新状态,使用双向绑定($$)
  • offset:触发刷新的拖动距离
  • friction:拖动的摩擦系数
  • onRefreshing:刷新事件回调

6.2 列表底部加载更多的实现

上拉加载更多功能主要通过ListItem的onAppear事件实现。当用户滚动到列表底部时,最后一个ListItem会出现在视图中,触发onAppear事件,从而调用loadMore方法加载更多数据。

6.3 条件渲染和动态样式

在新闻列表项中,我们使用了条件渲染和动态样式:

  • 根据news.isTop条件渲染置顶标签
  • 根据news.image条件渲染新闻图片
  • 根据news.imagenews.isTop动态调整布局和背景色

这种方式可以使列表项根据数据内容自适应显示不同的样式,提升用户体验。

七、完整代码结构

下面是完整的代码结构和样式设置:

部分 说明
数据模型 定义NewsType接口和初始新闻数据
状态变量 管理刷新、加载和分页状态
刷新方法 实现下拉刷新功能
加载方法 实现上拉加载更多功能
自定义Builder 定义刷新头部和加载尾部
页面结构 包含标题栏和新闻列表
列表实现 使用List和ListItem显示新闻
样式设置 设置颜色、字体、边距等样式

八、总结

本教程详细讲解了如何在HarmonyOS NEXT中实现一个具有下拉刷新和上拉加载更多功能的新闻列表应用 , 通过本教程,你应该能够掌握HarmonyOS NEXT中下拉刷新和上拉加载更多功能的基本实现方法,并能够应用到自己的项目中。在进阶篇中,我们将探讨如何增强这些功能,如添加动画效果、优化加载性能、实现更复杂的刷新交互等高级特性。

收藏00

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

全栈若城

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