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

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

效果展示


使用方法

ts 复制代码
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 组件

ts 复制代码
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)
  }
}

加载文字

ts 复制代码
@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)
  }
}
相关推荐
小五很懒2 小时前
Windows安装HDC工具及鸿蒙手机开启HDC调试
windows·华为·智能手机·harmonyos·hdc
HarmonyOS_SDK2 小时前
【FAQ】HarmonyOS SDK 闭源开放能力 —Map Kit(4)
harmonyos
time_silence2 小时前
ArkTS 组件事件、状态管理与资源管理
华为·arkts
光明_吖吼11 小时前
HarmonyOS应用开发者初级认证最新版– 2025/1/13号题库新版
华为·harmonyos
御承扬11 小时前
从零开始开发纯血鸿蒙应用之处理外部文件
华为·harmonyos·arkts·冷启动·热启动·外部文件处理
鸿蒙自习室11 小时前
鸿蒙UI开发——颜色选择器
华为·harmonyos·鸿蒙
程序猿阿伟13 小时前
《AI赋能鸿蒙Next,打造极致沉浸感游戏》
人工智能·游戏·harmonyos
guo_zhen_qian14 小时前
HarmonyOS命令行工具
华为·harmonyos
HarmonyOS_SDK21 小时前
意图框架习惯推荐方案,为用户提供个性化内容分发
harmonyos