HarmonyOS 鸿蒙 ArkTs(5.0.1 13)实现Scroll下拉到顶刷新/上拉触底加载,Scroll滚动到顶部

news2025/4/21 13:46:02

HarmonyOS 鸿蒙 ArkTs(5.0.1 13)实现Scroll下拉到顶刷新/上拉触底加载

效果展示

在这里插入图片描述
在这里插入图片描述

使用方法

import LoadingText from "../components/LoadingText"
import PageToRefresh from "../components/PageToRefresh"
import FooterBar from "../components/FooterBar"
class PageToRefreshController {
  onScrollTop = () => {}
}
@Entry
@Component
struct Index {
  //滚动回顶部方法start
  private PageToRefreshRef = new PageToRefreshController();
  onScrollTop(){
    this.PageToRefreshRef.onScrollTop()
  }
  //滚动回顶部方法end
  onSearch() {
    // 刷新数据
    this.loading = true;
    setTimeout(()=>{
      this.loading = false;
      this.simpleList = [1, 2, 3, 4, 5,6,7,8,9,10,11,12,13,14,15]
    },1000)
  }
  onReachBottom(){
    // 触底加载
    if(!this.finish){
      this.loading = true;
      setTimeout(()=>{
        this.loading = false;
        this.finish = true;
        this.simpleList = this.simpleList.concat([16,17,15,19,20,21,22,23,24,25,26,27,28,29,30])
      },1000)
    }
  }
  // 判断是否需要显示滚动到顶部的按钮(scroll滚动的位置)
  @State scrollY:number = 0;

  // 数据
  @State simpleList: Array<number> = [1, 2, 3, 4, 5,6,7,8,9,10,11,12,13,14,15];
  @State loading:boolean = false;
  @State finish:boolean = false;
  build() {
    Stack({ }) {
      Flex({ direction: FlexDirection.Column }) {
        // 顶部
        Column(){
          // 自定义顶部的组件
          Text('顶部标题').fontColor(0xffffff).fontSize(14)
        }
        .width('100%')
        .padding(10)
        .flexShrink(0)
        .backgroundColor(0xFC5531)
        .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])
        // 内容
        Stack(){
          //调用组件
          PageToRefresh({controller: this.PageToRefreshRef, scrollY: this.scrollY, refreshPull: () => {this.onSearch()}, reachBottom: () =>{this.onReachBottom()}}){
            Column(){
              Row(){
                // 自定义内容
                Text('这里可以定义滚动后固定在顶部的内容').fontColor(0xffffff).fontSize(14)
              }.width('100%').height(50).backgroundColor(0x232020).justifyContent(FlexAlign.Center)
              List() {
                ForEach(this.simpleList, (item: number, index: number) => {
                  ListItem(){
                    Row(){
                      Text(item.toString()).fontColor(0xffffff).fontSize(24)
                    }.width('100%').height(80).backgroundColor(0x1BA035).margin({bottom: 10}).justifyContent(FlexAlign.Center)
                  }
                }, (item: number) => item.toString())
                ListItem(){
                  LoadingText({loading: this.loading, finish: this.finish, onPullData: () => {
                    //点击直接加载数据
                    this.onReachBottom()
                  }})
                }
              }
            }.alignItems(HorizontalAlign.Start).justifyContent(FlexAlign.Start).constraintSize({minHeight: '100%'})
          }
          if(this.scrollY >= 50){
            Row(){
              Text('我已经固定在顶部啦').fontColor(0xffffff).fontSize(14)
            }.position({x:0,y:0}).width('100%').height(50).backgroundColor(0x232020).justifyContent(FlexAlign.Center)
          }
        }.flexGrow(1).flexShrink(1)
        //你自定义的底部tabbar组件(仅供示例)
        FooterBar({
          scrollTop: this.scrollY >= 500, //判断是否显示滚动到顶部
          onGoTop: () => {
            //点击滚动到顶部的方法
            this.onScrollTop();
          }
        }).flexShrink(0)
      }.width('100%').height('100%')
    }
  }
}

新建PageToRefresh 组件

import LoadingText from "./LoadingText"
class PageToRefreshController {
  onScrollTop = () => {}
}
@Component
export default struct PageToRefresh {
  refreshPull?: () => void
  reachBottom?: () => void
  scroller: Scroller = new Scroller()
  private controller: PageToRefreshController = new PageToRefreshController();
  aboutToAppear() {
    if (this.controller) {
      this.controller.onScrollTop = this.onScrollTop;
    }
  }
  private onScrollTop = () => {
    //滚动回顶部
    this.scroller.scrollTo({ xOffset: 0, yOffset: 0, animation: { duration: 1000, curve: Curve.Ease } })
  }
  @Link scrollY: number
  private currentOffsetY: number = 0;
  @State refreshStatus: boolean = false;
  @State refreshText: string = '正在刷新';
  @State pullUpText: string = '正在加载';
  @State isRefreshing: boolean = false;
  @State isCanLoadMore: boolean = false;
  @State ArrData: string[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
  @State newArr: string [] = ['10', '11']
  putDownPullUpRefresh(event?: TouchEvent): void {
    if (event === undefined) {
      return;
    }
    switch (event.type) {
      case TouchType.Down:
        this.currentOffsetY = event.touches[0].y;
        break;
      case TouchType.Move:
        let isDownPull = event.touches[0].y - this.currentOffsetY > 50;
        if (isDownPull && this.isCanLoadMore === false && this.scrollY <= 20) {
          this.refreshStatus = true;
        }
        if(this.scroller.isAtEnd()){
          console.log('滚动到底部')
          this.isCanLoadMore = true;
        }
        break;
      case TouchType.Cancel:
        break;
      case TouchType.Up:
        if (this.refreshStatus) {
          console.log('下拉刷新')
          this.refreshStatus = false;
          if(this.refreshPull) this.refreshPull();
        }
        if (this.isCanLoadMore) {
          console.log('上拉加载')
          this.isCanLoadMore = false;
          if(this.reachBottom) this.reachBottom();
        }
        break;
      default:
        break;
    }
  }

  @Builder
  putDown() {
    Row() {
      LoadingText({loading: true, finish: false, loadingText: this.refreshText})
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
  }

  @Builder
  PullUp() {
    Row() {
      LoadingText({loading: true, finish: false, loadingText: this.pullUpText})
    }
    .justifyContent(FlexAlign.Center)
    .width('94%')
    .height('5%')
  }
  @Builder
  slot() {
    Stack(){}.flexShrink(0)
  };
  @BuilderParam component: () => void = this.slot;

  build() {
    Column() {
      Scroll(this.scroller) {
        Column() {
          if (this.refreshStatus) {
            this.putDown()
          }
          this.component();
        }
      }
      .width('100%')
      .onWillScroll(() => {
        this.scrollY = this.scroller.currentOffset().yOffset;
      })
      .onTouch((event?: TouchEvent) => {
        this.putDownPullUpRefresh(event);
      })
    }.width('100%').height('100%').backgroundColor(0xf4f4f4)
  }
}

加载文字

@Component
export default struct LoadingText {
  onPullData?: () => void
  @Prop loadingText: string = "加载中...";
  @Prop loading: boolean = false;
  @Prop finishText: string = "- 我是有底线的 -";
  @Prop finish: boolean = false;
  build() {
    Row() {
      if(this.loading){
        LoadingProgress().width(20).height(20).margin({ right: 10 }).color(0x999999)
        Text(this.loadingText).fontSize(12).fontColor(0x999999).margin({left: 4})
      }else if(this.finish){
        Text(this.finishText).fontSize(12).fontColor(0x999999)
      }else{
        Text("轻轻上拉加载更多").fontSize(12).fontColor(0x999999).onClick(()=>{
          if (this.onPullData) {
            this.onPullData()
          }
        })
      }
    }.alignItems(VerticalAlign.Center).justifyContent(FlexAlign.Center).width('100%').height(24)
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2277442.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【开源免费】基于Vue和SpringBoot的欢迪迈手机商城(附论文)

本文项目编号 T 141 &#xff0c;文末自助获取源码 \color{red}{T141&#xff0c;文末自助获取源码} T141&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…

Cyber Security 101-Offensive Security-SQLMap: The Basics(sqlmap基础)

了解 SQL 注入并通过 SQLMap 工具利用此漏洞。 任务1&#xff1a;介绍 SQL 注入是一个普遍存在的漏洞&#xff0c;长期以来一直是热门 网络安全主题。要了解这个漏洞&#xff0c;我们必须首先 了解什么是数据库以及网站如何与数据库交互。 数据库是可以存储、修改和 检索。它…

【数据结构-堆】力扣1792. 最大平均通过率

一所学校里有一些班级&#xff0c;每个班级里有一些学生&#xff0c;现在每个班都会进行一场期末考试。给你一个二维数组 classes &#xff0c;其中 classes[i] [passi, totali] &#xff0c;表示你提前知道了第 i 个班级总共有 totali 个学生&#xff0c;其中只有 passi 个学…

USRP,FM解调程序

USRP&#xff0c;FM解调程序

洛谷 P1101 单词方阵刷题笔记

题目 https://www.luogu.com.cn/problem/P1101 题目要求输出包含 yizhong 所有方向排列的矩阵图 观察答案除了yizhong 均为星号 因此我们可以用bool数组来标记每个位置的状态 定义星号为无效状态 false 我们对原矩阵图 进行遍历 每当找到一个y就试一下它各个方向是否满…

WPS excel使用宏编辑器合并 Sheet工作表

使用excel自带的工具合并Sheet表&#xff0c;我们会发现需要开通WPS会员才能使用合并功能&#xff1b; 那么WPS excel如何使用宏编辑器进行合并 Sheet表呢&#xff1f; 1、首先我们要看excel后缀是 .xlsx 还是 .xls &#xff1b;如果是.xlsx 那么 我们需要修改为 .xls 注…

WPF、控件模板(ControlTemplate)和数据模板(DataTemplate)

前言 在 WPF 中&#xff0c;控件种类丰富且功能非常完善。一个显著的优点是 WPF 提供了强大的自定义能力和灵活的用户界面表现&#xff0c;能够满足各种复杂的应用需求。其中&#xff0c;ControlTemplate 和 DataTemplate 是两个非常重要的概念&#xff0c;分别用于自定义控件…

Redis十大数据类型详解

Redis&#xff08;一&#xff09; 十大数据类型 redis字符串&#xff08;String&#xff09; string是redis最基本的类型&#xff0c;一个key对应一个value string类型是二进制安全的&#xff0c;意思是redis的string可以包含任何数据。例如说是jpg图片或者序列化对象 一个re…

Python Wi-Fi密码测试工具

Python Wi-Fi测试工具 相关资源文件已经打包成EXE文件&#xff0c;可双击直接运行程序&#xff0c;且文章末尾已附上相关源码&#xff0c;以供大家学习交流&#xff0c;博主主页还有更多Python相关程序案例&#xff0c;秉着开源精神的想法&#xff0c;望大家喜欢&#xff0c;点…

qml AngleDirection详解

1、概述 AngleDirection 是 QML&#xff08;Qt Meta Language&#xff09;中用于定义粒子发射方向的一个类&#xff0c;它属于 Qt Quick Particles 模块。AngleDirection 通过设置角度范围来控制粒子从发射器射出时的初始方向。这个类在创建具有特定发射模式的粒子效果时非常有…

VSCode使用纪要

1、常用快捷键 1&#xff09;注释 ctrl? 单行注释&#xff0c; altshifta 块注释&#xff0c; 个人测试&#xff0c;ctrl? 好像也能块注释 2&#xff09;开多个项目 可以先开一个新窗口&#xff0c;再新窗口打开另一个项目&#xff0c;这时就是同时打开多个项目了。 打开…

单独编译QT子模块

单独编译QT子模块 系统 win qt-everywhere-src-5.12.12 下载源码&#xff1a; https://download.qt.io/archive/qt/5.12/5.12.12/single/ 参考&#xff1a; https://doc.qt.io/qt-5/windows-building.html 安装依赖 https://doc.qt.io/qt-5/windows-requirements.html Per…

浙江安吉成新照明电器:Acrel-1000DP 分布式光伏监控系统应用探索

安科瑞吕梦怡 18706162527 摘 要&#xff1a;分布式光伏发电站是指将光伏发电组件安装在用户的建筑物屋顶、空地或其他适合的场地上&#xff0c;利用太阳能进行发电的一种可再生能源利用方式&#xff0c;与传统的大型集中式光伏电站相比&#xff0c;分布式光伏发电具有更灵活…

DAMA GDPA 备考笔记(二)

1. 考点分布 2. 第二章 数据处理伦理知识点总结 伦理是建立在是非观念上的行为准则。伦理准则通常侧重于公平、尊重、责任、诚信、质量、可靠性、透明度和信任等方面。数据伦理是一项社会责任问题不是法律问题。 度量指标&#xff1a;培训员工人数、合规/不合规事件、企业高管…

Unity中实现倒计时结束后干一些事情

问题描述&#xff1a;如果我们想实现在一个倒计时结束后可以执行某个方法&#xff0c;比如挑战成功或者挑战失败&#xff0c;或者其他什么的比如生成boss之类的功能&#xff0c;而且你又不想每次都把代码复制一遍&#xff0c;那么就可以用下面这种方法。 结构 实现步骤 创建一…

【Elasticsearch】filterQuery过滤查询

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

带头双向循环链表(数据结构初阶)

文章目录 双向链表链表的分类概念与结构实现双向链表定义链表结构链表打印判空申请结点初始化头插尾插头删尾删查找指定位置插入和删除销毁链表 顺序表和链表的分析结语 欢迎大家来到我的博客&#xff0c;给生活来点impetus&#xff01;&#xff01; 这一节我们学习双向链表&a…

在eNSp上telnet一下吧

在上篇博客&#xff1a;DNS 我们提到了telnet和设备带外管理、带内管理&#xff0c;它确实是非常有趣的一个知识点哦&#xff0c;接下来我们一起来学习学习吧~ Telnet&#xff08;远程登陆协议&#xff09; Telnet基于TCP 23号端口&#xff0c;典型的C/S架构模式&#xff0c;是…

Spring MVC复杂数据绑定-绑定集合

【图书介绍】《SpringSpring MVCMyBatis从零开始学&#xff08;视频教学版&#xff09;&#xff08;第3版&#xff09;》_【新华文轩】springspring mvcmybatis从零开始学(视频教学版) 第3版 正版-CSDN博客 《SpringSpring MVCMyBatis从零开始学(视频教学版)&#xff08;第3版…

基于禁忌搜索算法的TSP问题最优路径搜索matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于禁忌搜索算法的TSP问题最优路径搜索&#xff0c;旅行商问题&#xff08;TSP&#xff09;是一个经典的组合优化问题。其起源可以追溯到 19 世纪初&#xff0c;…