HarmonyOS 鸿蒙Next 使用 Scroll 及其 nested 属性,实现一个有 header,body 为 Tabs,Tabcontent 里面为 List

发布于 1周前 作者 itying888 来自 鸿蒙OS

HarmonyOS 鸿蒙Next 使用 Scroll 及其 nested 属性,实现一个有 header,body 为 Tabs,Tabcontent 里面为 List

使用 Scroll 及其 nested 属性,实现一个有 header ,body 为 Tabs,Tabcontent 里面为 List,使用 PullToRefresh 如何实现每个列表的下拉刷新和上拉加载,并能和最外层 Scroll 实现滚动的联动 大众号新闻列表上拉加载和下拉刷新功能,下拉统一刷新,上拉单独加载每个 TabContent


更多关于HarmonyOS 鸿蒙Next 使用 Scroll 及其 nested 属性,实现一个有 header,body 为 Tabs,Tabcontent 里面为 List的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复
外层使用Refresh组件:

文档: Refresh-滚动与滑动-ArkTS组件-ArkUI(方舟UI框架)-应用框架 - 华为HarmonyOS开发者 (huawei.com)

参考demo:

import { PullToRefresh, PullToRefreshConfigurator } from '[@ohos](/user/ohos)/pulltorefresh'
[@Entry](/user/Entry)
[@Component](/user/Component)
struct PullRefreshPage {
  [@State](/user/State) currentIndex: number = 0
  private dataNumbers: string[] = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'];
  private tabList2Numbers: string[] = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十'];
  [@State](/user/State) data: string[] = [];
  [@State](/user/State) tabList2: string[] = [];
  private scroller: Scroller = new Scroller();
  tabController: TabsController = new TabsController()
  private refreshConfigurator: PullToRefreshConfigurator = new PullToRefreshConfigurator();
  [@State](/user/State) isRefreshing: boolean = false
  [@State](/user/State) isLoading: boolean = false
  aboutToAppear() {
    this.refreshConfigurator.setHasRefresh(false)
    for (let i = 0; i < 20; i++) {
      this.data.push(`列表item${i}`)
      this.tabList2.push(`tab2_item${i}`)
    }
  }
  [@Builder](/user/Builder)
  customRefreshComponent() {
    Stack() {
      Row() {
        LoadingProgress().height(32)
        if (this.isLoading) {
          Text("正在刷新").fontSize(16).margin({left:20})
        }
      }
      .alignItems(VerticalAlign.Center)
      .justifyContent(FlexAlign.Center)
    }.width("100%").align(Alignment.Center)
  }
  build() {
    Refresh({ refreshing: $$this.isRefreshing, builder:this.customRefreshComponent()}) {
      Scroll() {
        Column(){
          Text("Header")
            .width("100%")
            .height(140)
            .backgroundColor('#0080DC')
            .textAlign(TextAlign.Center)
          Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.tabController }) {
            TabContent() {
              this.listBuilder()
            }.tabBar(this.TabBuilder('TabItem_1', 0))
            TabContent() {
              Column(){
                this.list2Builder()
              }.width('100%').height('100%').backgroundColor(Color.Pink)
            }.tabBar(this.TabBuilder('TabItem_2', 1))
          }
          .height('100%')
          .vertical(false)
          .onChange((index: number) => {
            this.currentIndex = index
          })
        }.width("100%")
      }
      .edgeEffect(EdgeEffect.None)
      .backgroundColor('#DCDCDC')
      .scrollBar(BarState.Off)
      .width('100%')
      .height('100%')
    }
    .onRefreshing(() => {
      this.isLoading = true
      setTimeout(() => {
        this.isRefreshing = false
        this.isLoading = false
        this.data = this.dataNumbers;
        this.tabList2 = this.tabList2Numbers
      }, 2000)
    })
    .backgroundColor(0x89CFF0)
  }
  [@Builder](/user/Builder) TabBuilder(label: string, index: number) {
    Column() {
      Text(label)
        .fontSize(16)
        .lineHeight(22)
        .margin({ top: 6, bottom: 6 })
      Divider()
        .strokeWidth(2)
        .width(60)
        .color('#007DFF')
        .opacity(this.currentIndex === index ? 1 : 0)
    }.width('100%')
  }
  [@Builder](/user/Builder)
  listBuilder() {
    PullToRefresh({
      // 必传项,列表组件所绑定的数据
      data: $data,
      // 必传项,需绑定传入主体布局内的列表或宫格组件
      scroller: this.scroller,
      // 必传项,自定义主体布局,内部有列表或宫格组件
      customList: () => {
        // 一个用[@Builder](/user/Builder)修饰过的UI方法
        this.getList1View()
      },
      refreshConfigurator: this.refreshConfigurator,
      // 可选项,上拉加载更多回调
      onLoadMore: () => {
        return new Promise<string>((resolve, reject) => {
          // 模拟网络请求操作,请求网络2秒后得到数据,通知组件,变更列表数据
          setTimeout(() => {
            resolve('');
            this.data.push("tab1增加的条目" + this.data.length)
          }, 2000);
        });
      },
      customLoad: null,
      customRefresh: null,
    })
  }
  [@Builder](/user/Builder)
  list2Builder() {
    PullToRefresh({
      // 必传项,列表组件所绑定的数据
      data: $tabList2,
      // 必传项,需绑定传入主体布局内的列表或宫格组件
      scroller: this.scroller,
      // 必传项,自定义主体布局,内部有列表或宫格组件
      customList: () => {
        this.getList2View()
      },
      refreshConfigurator: this.refreshConfigurator,
      // 可选项,上拉加载更多回调
      onLoadMore: () => {
        return new Promise<string>((resolve, reject) => {
          // 模拟网络请求操作,请求网络2秒后得到数据,通知组件,变更列表数据
          setTimeout(() => {
            resolve('');
            this.tabList2.push("tab2增加的条目" + this.tabList2.length)
          }, 2000);
        });
      },
      customLoad: null,
      customRefresh: null,
    })
  }
  [@Builder](/user/Builder)
  private getList1View() {
    List({ space: 10, scroller: this.scroller }) {
      ForEach(this.data, (item: number) => {
        ListItem() {
          Text("item" + item).fontSize(16)
        }
        .backgroundColor(Color.White)
        .height(70)
        .width("100%")
        .borderRadius(10)
      }, (item: string) => item)
    }.width("100%")
    .height('100%')
    .edgeEffect(EdgeEffect.None)
    .divider({ strokeWidth: 1, color: 0x222222 })
    .nestedScroll({
      scrollForward: NestedScrollMode.PARENT_FIRST,
      scrollBackward: NestedScrollMode.SELF_FIRST
    })
  }
  [@Builder](/user/Builder)
  private getList2View() {
    List({ space: 10, scroller: this.scroller }) {
      ForEach(this.tabList2, (item: number) => {
        ListItem() {
          Text("item" + item).fontSize(16)
        }
        .backgroundColor(Color.White)
        .height(70)
        .width("100%")
        .borderRadius(10)
      }, (item: string) => item)
    }.width("100%")
    .height('100%')
    .edgeEffect(EdgeEffect.None)
    .divider({ strokeWidth: 1, color: 0x222222 })
    .nestedScroll({
      scrollForward: NestedScrollMode.PARENT_FIRST,
      scrollBackward: NestedScrollMode.SELF_FIRST
    })
  }
}

更多关于HarmonyOS 鸿蒙Next 使用 Scroll 及其 nested 属性,实现一个有 header,body 为 Tabs,Tabcontent 里面为 List的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next系统中,使用Scroll组件及其nested属性可以实现一个带有header、body为Tabs、TabContent里面为List的布局。以下是一个简要实现思路:

  1. 布局结构

    • 外层使用Scroll组件,设置nested属性为true以允许嵌套滚动。
    • Scroll组件内首先放置一个header,可以是任何自定义组件。
    • 接着是Tabs组件作为body,设置相应的Tab项。
    • 每个Tab项的内容为List组件,用于展示列表数据。
  2. 实现细节

    • 确保Scroll组件的nested属性为true,以允许List组件在Tabs内部独立滚动。
    • Tabs组件设置onTabSelected事件监听器,以处理Tab切换逻辑。
    • 每个Tab对应的List组件需要独立管理其数据源和滚动状态。
  3. 注意事项

    • 在处理嵌套滚动时,注意滚动事件的传递和拦截,避免滚动冲突。
    • 确保TabsList组件的布局参数正确,避免布局错乱。

通过上述步骤,你可以在HarmonyOS鸿蒙Next系统中实现一个带有header、body为Tabs、TabContent里面为List的复杂布局。如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部