Skip to content

鸿蒙上拉加载下拉刷新

效果

注意

注意

  1. 经本人实地测试.List 组件的 onReachEnd 和 onReachStart 方法 有点小问题
  • onReachEnd 方法会在页面加载时触发一次,而不是在滚动到底部时触发

  • onReachStart 方法没法设置安全距离.也就是说页面滚动到顶部就会触发

期待后续改进

  1. 所以要实现下拉只有通过 Refresh 组件,刷新页面只有自己写个等待动画.然后赋值 否则 onReachEnd 会自己触发

代码

ts

@Entry
@Component
struct Index {
    // 每页个数
    @State pageSize: number = 5;
    // 当前页
    @State currentPage: number = 1;
    // 刷新状态
    @State isRefreshing: boolean = false;
    // 第一页数据
    @State OnePage: string[] = ["1", "2", "3", "4", "5"]
    // 第二页数据
    @State TwoPage: string[] = ["6", "7", "8", "9", "10"]
    // 第三页数据
    @State ThirdPage: string[] = ["11", "12", "13", "14", "15"]
    // 最终数据
    @State List: string[] = []
    // 刷新状态
    @State ShuaXinstate: RefreshStatus = RefreshStatus.Inactive
    // 上拉加载
    @State isLoading: boolean = false;
    @State isEnd: boolean = false;
    // 滚动控制器
    private scrollControl: Scroller = new Scroller()
    // 点击刷新页面
    @State refreshPageFlag: boolean = false

    // 刷新区域文本
    @Builder
    customRefreshComponent() {
        if (this.ShuaXinstate == RefreshStatus.OverDrag || this.ShuaXinstate == RefreshStatus.Refresh) {
            Stack() {
                Row() {
                    LoadingProgress().height(32)
                    Text("刷新中...").fontSize(16).margin({ left: 20 })
                }
                .alignItems(VerticalAlign.Center)
            }
            .align(Alignment.Center)
            .clip(true)
            // 设置最小高度约束保证自定义组件高度随刷新区域高度变化时自定义组件高度不会低于minHeight。
            .constraintSize({ minHeight: 32 })
            .width("100%")
        } else {
            Text("")
        }

    }

    @Builder
    loadingBuilder() {
        Column({ space: 20 }) {
            Text("加载中").fontSize(16).fontWeight(FontWeight.Medium).fontColor('#7e8892')
        }
        .width('100%')
        .layoutWeight(1)
        .justifyContent(FlexAlign.Center)
    }

    aboutToAppear(): void {

        this.List = [...this.OnePage]
    }

    // 下拉刷新
    handleReachStart() {

        setTimeout(() => {
            console.log("触发了!!!")
            this.currentPage = 1;
            this.List = [...this.OnePage]
            this.isRefreshing = false;
        }, 1000)
    }

    // 上拉加载
    handleReachEnd() {
        if (this.isEnd) {
            console.log("没数据了都结束了")
            return
        }
        if (!this.isLoading) {
            this.isLoading = true;
            setTimeout(() => {
                console.log("上拉加载")
                this.currentPage += 1;
                if (this.currentPage > 3) {
                    this.List = [...this.OnePage, ...this.TwoPage, ...this.ThirdPage]
                    this.isEnd = true;
                    this.isLoading = false;
                    return
                }
                if (this.currentPage == 2) {
                    this.List = [...this.OnePage, ...this.TwoPage]
                    this.isLoading = false;
                    return
                }
                if (this.currentPage == 3) {
                    this.List = [...this.OnePage, ...this.TwoPage, ...this.ThirdPage]
                    this.isLoading = false;
                    return
                }

            }, 1000)
        }

    }

    // 重新进入页面
    ShuaXinPage() {
        this.refreshPageFlag = true
        setTimeout(() => {
            console.log("刷新了!!!")
            this.currentPage = 1;
            this.List = [...this.OnePage]
            this.refreshPageFlag = false;
        }, 1000)
    }

    build() {
        Column() {
            if (this.refreshPageFlag) {
                this.loadingBuilder()
            } else {
                Stack({ alignContent: Alignment.BottomEnd }) {
                    // 滑动的数据
                    Refresh({ refreshing: $$this.isRefreshing, builder: this.customRefreshComponent() }) {
                        List({ space: 50, scroller: this.scrollControl }) {
                            ForEach(this.List, (item: string, index) => {
                                ListItem() {
                                    Row() {
                                        Text(item).statTextStyle()
                                    }
                                }
                                .padding(10)
                                .width('90%')
                                .margin({ top: 10, left: '5%', bottom: 20 })
                                .borderRadius(10)
                                .shadow({ radius: 20 })
                            })
                        }
                        .width('100%')
                        .height('100%')
                        .alignListItem(ListItemAlign.Center)
                        .scrollBar(BarState.On)
                        .onScrollIndex((start: number, end: number) => {
                            console.log(end.toString())
                            console.log(this.List.length.toString())
                            if (end >= this.List.length - 1) {
                                console.log("到达了底部")
                                this.handleReachEnd()
                            }
                        })

                        // .onReachEnd(() => {
                        //     console.log("到达了底部")
                        //     this.handleReachEnd()
                        // })

                    }
                    // 当下拉距离>安全距离 是否执行下拉刷新
                    .pullToRefresh(true)
                    // 设置安全距离只有大于等于这个数字才会下拉刷新
                    .refreshOffset(100)
                    // 状态改变发生的回调
                    .onStateChange((state: RefreshStatus) => {
                        console.log("----")
                        console.log(state.toString())
                        this.ShuaXinstate = state;
                    })
                    // 进入刷新状态发生的回调
                    .onRefreshing(() => {
                        this.handleReachStart()
                    })
                    // 监听下拉距离发生变化时触发回调。
                    .onOffsetChange((value: number) => {
                        console.log(value.toString())
                    })

                    // 按钮
                    Column({ space: 20 }) {
                        Button({ type: ButtonType.Circle }) {
                            Image($r('app.media.ic_top'))
                                .height(14)
                                .width(14)

                        }
                        .height(40)
                        .width(40)
                        .backgroundColor(Color.Black)
                        .opacity(0.5)
                        .onClick(() => {
                            //todo: 返回顶部
                            console.log("点击了啊")
                            console.log(JSON.stringify(this.scrollControl))
                            this.scrollControl.scrollTo({
                                xOffset: 0,
                                yOffset: 0,
                                animation: {
                                    curve: Curve.EaseIn,
                                    duration: 1000,
                                    canOverScroll: true
                                }
                            })
                        })

                        Button({ type: ButtonType.Circle }) {
                            Image($r('app.media.ic_refresh'))
                                .height(14)
                                .width(14)
                        }
                        .height(40)
                        .width(40)
                        .backgroundColor(Color.Black)
                        .opacity(0.5)
                        .onClick(() => {
                            // this.handleShuaxin()

                            this.ShuaXinPage()
                        })
                    }
                    .offset({ x: -20, y: -50 })
                }.width('100%').height('100%')
            }


        }
    }
}


@Extend(Text)
function statTextStyle() {
    .width('100%')
    .fontSize(16)
    .height(100)
    .textAlign(TextAlign.Center)
    .fontWeight(FontWeight.Medium)
    .fontColor(Color.Black)
}