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

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)
  }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《自动驾驶与机器人中的SLAM技术》ch9:自动驾驶车辆的离线地图构建

目录 1 点云建图的流程 2 前端实现 2.1 前端流程 2.2 前端结果 3 后端位姿图优化与异常值剔除 3.1 两阶段优化流程 3.2 优化结果 ① 第一阶段优化结果 ② 第二阶段优化结果 4 回环检测 4.1 回环检测流程 ① 遍历第一阶段优化轨迹中的关键帧。 ② 并发计算候选回环对…

鸿蒙面试 2025-01-10

写了鉴权工具&#xff0c;你在项目中申请了那些权限&#xff1f;&#xff08;常用权限&#xff09; 位置权限 &#xff1a; ohos.permission.LOCATION_IN_BACKGROUND&#xff1a;允许应用在后台访问位置信息。 ohos.permission.LOCATION&#xff1a;允许应用访问精确的位置信息…

Windows图形界面(GUI)-QT-C/C++ - QT控件创建管理初始化

公开视频 -> 链接点击跳转公开课程博客首页 -> ​​​链接点击跳转博客主页 目录 控件创建 包含对应控件类型头文件 实例化控件类对象 控件设置 设置父控件 设置窗口标题 设置控件大小 设置控件坐标 设置文本颜色和背景颜色 控件排版 垂直布局 QVBoxLayout …

Unreal Engine 5 C++ Advanced Action RPG 七章笔记

第七章 Ranged Enemy 2-Ranged Enemy Starting Weapon 制作新敌人的流程准备 新敌人的武器起始的状态数据自己的战斗能力投射能力自己的行为树 创建角色,添加武器,添加数据,就是继承之前的基类敌人的 运行结果 3-Glacer Starting Stats 看看就行,就是复制曲线表格更改数…

funcaptcha手势指向验证码识别

注意&#xff0c;本文只提供学习的思路&#xff0c;严禁违反法律以及破坏信息系统等行为&#xff0c;本文只提供思路 如有侵犯&#xff0c;请联系作者下架 本文滑块识别已同步上线至OCR识别网站&#xff1a; http://yxlocr.nat300.top/ocr/other/21 该验证码会给出某物品所有的…

GAMES101学习笔记(三):Rasterization 光栅化(三角形的离散化、抗锯齿、深度测试)

文章目录 视口变换 Viewport三角形网格 Triangle Mesh采样 Sampling走样/反走样 Aliasing/Antialiasing采样频率、空间域与频率域深入理解采样、走样、反走样反走样总结深度测试 Depth testing 课程资源&#xff1a;GAMES101-现代计算机图形学入门-闫令琪 Lec5 ~ Lec6 学习笔记…

vscode 扩展Cline、Continue的差别?

Cline和Continue都是VSCode的AI编程插件&#xff0c;它们在功能、用户体验、性能、适用场景以及配置和使用步骤等方面存在一些差别&#xff1a; 一、功能差异 编辑功能 Cline&#xff1a;能够分析项目的文件结构和源代码抽象语法树&#xff08;AST&#xff09;&#xff0c;通…

鸿蒙打包发布

HarmonyOS应用/元服务发布&#xff08;打包发布&#xff09; https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V13/ide-publish-app-V13?catalogVersionV13 密钥&#xff1a;包含非对称加密中使用的公钥和私钥&#xff0c;存储在密钥库文件中&#xff0c;格式…

晨辉面试抽签和评分管理系统之九:随机编排考生的分组(以教师资格考试面试为例)

晨辉面试抽签和评分管理系统&#xff08;下载地址:www.chenhuisoft.cn&#xff09;是公务员招录面试、教师资格考试面试、企业招录面试等各类面试通用的考生编排、考生入场抽签、候考室倒计时管理、面试考官抽签、面试评分记录和成绩核算的面试全流程信息化管理软件。提供了考生…

sparkRDD教程之必会的题目

1.前期准备 &#xff08;1&#xff09;看看上一期的博客&#xff0c;最好跟着上一期的博客把sparkRDD的基本命令给熟练掌握后&#xff0c;再来做这篇文章的任务。 上一期的博客&#xff1a;sparkRDD教程之基本命令-CSDN博客 &#xff08;2&#xff09;新建文件task6.scala …

stack和queue专题

文章目录 stack最小栈题目解析代码 栈的压入弹出序列题目解析代码 queue二叉树的层序遍历题目解析代码 stack stack和queue都是空间适配器 最小栈 最小栈的题目链接 题目解析 minst是空就进栈&#xff0c;或者是val < minst.top()就进栈 代码 class MinStack { public:M…

欧拉路径算法

欧拉图&#xff1a; 对于应该连通图G&#xff0c;有&#xff1a; 1欧拉路径&#xff1a;一条路径&#xff0c;它能够不重复地遍历完所有的边&#xff0c;这个性质很像不重复地一笔画完所有边&#xff0c;所以有些涉及到欧拉路径的问题叫做一笔画问题。 2欧拉回路&#xff1a…

【C#设计模式(23)——模板方法模式(Template Method Pattern)】

前言 在抽象类中封装算法的结构&#xff0c;具体的实现步骤由子类定义&#xff0c;从而达到不改变算法结构的&#xff0c;允许子类重定义方法内容。代码 public abstract class Teamplate {public void TeamplateMethod(){Step1();Step2();Step3();}protected abstract void …

MyBatis——XML映射文件

在MyBatis中&#xff0c;既可以通过注解的方式配置SQL语句&#xff0c;也可以通过XML映射文件的方式配置SQL语句。对于简单的SQL语句建议直接通过注解的方式配置SQL语句&#xff1a; Delete("delete from user where id#{id}") Integer deleteById(Integer id);但是…

Mysql--运维篇--安全性(数据库访问控制,最小权限原则,表空间加密,TLS加密,证书签发,SQL注入及防范等)

一、数据库访问控制 MySQL的访问控制是确保数据库安全的关键机制之一。通过合理的用户权限管理和访问控制策略&#xff0c;可以防止未经授权的用户访问、修改或删除敏感数据。 1、MySQL访问控制的工作原理 MySQL使用基于用户的访问控制模型&#xff0c;每个用户都有特定的权…

抽奖滚动功能

代码 <template><div class"box"><video class"video" src"../../assets/video/底层.mp4" loop autoplay muted></video><img class"choujiang" src"../../assets/image/抽奖1.png" alt"&…

【Python】Python之locust压测教程+从0到1demo:基础轻量级压测实战(1)

文章目录 一、什么是Locust二、Locust 架构组成三、实战 Demo准备一个可调用的接口编写一个接口测试用例编写一个性能测试用例执行性能测试用例代码1、通过 Web UI 执行&#xff08;GUI模式&#xff09;2、通过命令行执行&#xff08;非GUI模式&#xff09; 小知识&#xff1a;…

Microsoft

Microsoft Word目录1.目录编号与文字的间距设置2. 目录编号缩进设置 Excel函数MID&#xff08;提取字符&#xff09;CONCAT&#xff08;组合字符串&#xff09;EXACT&#xff08;比较字符串&#xff09; PowerPointwindows 11 恢复右键传统菜单 Word 目录 1.目录编号与文字的…

用 Python 处理 CSV 和 Excel 文件

&#x1f496; 欢迎来到我的博客&#xff01; 非常高兴能在这里与您相遇。在这里&#xff0c;您不仅能获得有趣的技术分享&#xff0c;还能感受到轻松愉快的氛围。无论您是编程新手&#xff0c;还是资深开发者&#xff0c;都能在这里找到属于您的知识宝藏&#xff0c;学习和成长…

JS后盾人--再一次的走进JS?

程序跑起来与避免延迟 如果你讲JS&#xff0c;你就不可能只讲JS 后盾人说开发就要用VScode&#xff08;确实&#xff0c;Windows和Linux都可以跑&#xff09; 然后就是第一天开发的时候装的那些插件 前端访问流程基本分析 托管到服务器上的东西&#xff0c;谁访问下载到谁的…