HarmonyOS 鸿蒙Next 如何获取Grid组件中 Item距离顶部的偏移量

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

HarmonyOS 鸿蒙Next 如何获取Grid组件中 Item距离顶部的偏移量

Grid的一些使用场景,如附近中红色区域是一个Grid组件

1、如何让Grid自动滚动到顶部?比如说在全部这个Tab中滑动到中间的位置,切换到背包后再又切换到全部Tab,期待Grid是滑动到顶部的。

2、如何获取Grid滑动后监听到可见的第一个Item距离Grid的偏移量?比如我在全部这个Tab中滑动到了中间位置,关闭了面板后,下载打开面板期待全部这个分类下滑动到关闭的位置?


更多关于HarmonyOS 鸿蒙Next 如何获取Grid组件中 Item距离顶部的偏移量的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

可以参考如下demo: // xxx.ets

@Entry

@Component

struct TabsExample {

  @State fontColor: string = '#182431'

  @State selectedFontColor: string = '#007DFF'

  @State currentIndex: number = 0

  private controller: TabsController = new TabsController()

  private scroller: Scroller = new Scroller()

  private scroller1: Scroller = new Scroller()

  @State numbers1: String[] = ['0', '1', '2', '3', '4']

  @State numbers2: String[] = ['0', '1', '2', '3', '4', '5']

  curScrollOffset1: number = 0

  @State clickedContent: string = ""

  layoutOptions3: GridLayoutOptions = {

    regularSize: [1, 1],

    onGetRectByIndex: (index: number) => {

      if (index == 0) {

        return [0, 0, 1, 1]

      } else if (index == 1) {

        return [0, 1, 2, 2]

      } else if (index == 2) {

        return [0, 3, 3, 3]

      } else if (index == 3) {

        return [3, 0, 3, 3]

      } else if (index == 4) {

        return [4, 3, 2, 2]

      } else {

        return [5, 5, 1, 1]

      }

    }

  }

  @Builder

  tabBuilder(index: number, name: string) {

    Column() {

      Text(name)

        .fontColor(this.currentIndex === index ? this.selectedFontColor : this.fontColor)

        .fontSize(16)

        .fontWeight(this.currentIndex === index ? 500 : 400)

        .lineHeight(22)

        .margin({ top: 17, bottom: 7 })

      Divider()

        .strokeWidth(2)

        .color('#007DFF')

        .opacity(this.currentIndex === index ? 1 : 0)

    }.width('100%')

  }

  build() {

    Column() {

      Button('tabs停止滚动并存储位置')

        .width(100).height(100)

        .onClick(()=>{

          AppStorage.setOrCreate('this.currentIndex', this.currentIndex); //记录切换的tabs中的index, 因为这里index === 1为例 记录滚动偏移量,可以this.currentIndex设置为1

          AppStorage.setOrCreate('this.curScrollOffset1', this.curScrollOffset1);  // 以index === 1为例 记录滚动偏移量

        })

      Button('点击滚动到之前的位置')

        .width(100).height(100)

        .onClick(()=>{

          this.currentIndex = Number(AppStorage.get('this.currentIndex')) // 获取记录切换的tabs中的index

          this.curScrollOffset1 = Number(AppStorage.get('this.curScrollOffset1')) //获取 以index === 1为例 记录滚动偏移量

          this.scroller.scrollTo({ xOffset: 0, yOffset: this.curScrollOffset1, animation: { duration: 100, curve: Curve.Ease } }) //由于只能上下移动,所以改变yOffset即可

        })

      Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {

        TabContent() {

          Scroll(this.scroller) {

            Grid() {

              ForEach(this.numbers1, (day: string) => {

                ForEach(this.numbers2, (day: string) => {

                  GridItem() {

                    Text(day)

                      .fontSize(16)

                      .backgroundColor(0xF9CF93)

                      .width('100%')

                      .height('100%')

                      .textAlign(TextAlign.Center)

                  }

                }, (day: string) => day)

              }, (day: string) => day)

            }

            .columnsTemplate('1fr 1fr 1fr 1fr 1fr')

            .rowsTemplate('1fr 1fr 1fr 1fr 1fr')

            .columnsGap(10)

            .rowsGap(10)

            .width('100%')

            .height('150%')

          }.backgroundColor('#ffffed00')

        }

        .tabBar(this.tabBuilder(0, 'green'))

        TabContent() {

          Scroll(this.scroller1) {

            Grid() {

              ForEach(this.numbers1, (day: string) => {

                ForEach(this.numbers2, (day: string) => {

                  GridItem() {

                    Text(day)

                      .fontSize(16)

                      .backgroundColor(0xF9CF93)

                      .width('100%')

                      .height('100%')

                      .textAlign(TextAlign.Center)

                  }

                }, (day: string) => day)

              }, (day: string) => day)

            }

            .columnsTemplate('1fr 1fr 1fr 1fr 1fr')

            .rowsTemplate('1fr 1fr 1fr 1fr 1fr')

            .columnsGap(10)

            .rowsGap(10)

            .width('100%')

            .height('150%')

          }

          .backgroundColor('#00ef2323')

          .onWillScroll((xOffset: number, yOffset: number, scrollState: ScrollState) => {

            this.curScrollOffset1 += yOffset  //上下滑动,只记录yOffset即可

            console.info('this.curScrollOffset1' + ' ' + this.curScrollOffset1)

          })

        }

        .tabBar(this.tabBuilder(1, 'blue'))

      }

      .vertical(false)

      .barMode(BarMode.Fixed)

      .barWidth(360)

      .barHeight(56)

      .animationDuration(400)

      .onChange((index: number) => {

        if(index === 0){

          this.scroller.scrollTo({ xOffset: 0, yOffset: 0, animation: { duration: 100, curve: Curve.Ease } })  // index切换时,数据滚动到顶部

        }else{

          this.scroller1.scrollTo({ xOffset: 0, yOffset: 0, animation: { duration: 100, curve: Curve.Ease } }) // 如果想验证index === 2的偏移量是否正确,可以去掉此段代码,记录偏移量

        }

        this.currentIndex = index

        console.log("this.currentIndex"+ this.currentIndex)

      })

      .width(360)

      .height('100%')

      .margin({ top: 52 })

      .backgroundColor('#F1F3F5')

    }

    .width('100%').height('100%')

  }

}

scrollTo: 滑动到指定位置。

参考demo: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-container-scroll-V5#scrollto

onWillScroll: 回调当前帧将要滚动的偏移量和当前滚动状态和滚动操作来源,其中回调的偏移量为计算得到的将要滚动的偏移量值,并非最终实际滚动偏移。可以通过该回调返回值指定Scroll将要滚动的偏移。

参考链接: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-container-scroll-V5#onwillscroll12

如果Grid外层不想嵌套Scroll,

可以参考如下demo:

@Entry

@Component

struct TabsExample {

  @State fontColor: string = '#182431'

  @State selectedFontColor: string = '#007DFF'

  @State currentIndex: number = 0

  private controller: TabsController = new TabsController()

  private scroller: Scroller = new Scroller()

  private scroller1: Scroller = new Scroller()

  @State numbers1: String[] = ['0', '1', '2', '3', '4']

  @State numbers2: String[] = ['0', '1', '2', '3', '4', '5']

  curScrollOffset1: number = 0

  @State clickedContent: string = ""

  layoutOptions3: GridLayoutOptions = {

    regularSize: [1, 1],

    onGetRectByIndex: (index: number) => {

      if (index == 0) {

        return [0, 0, 1, 1]

      } else if (index == 1) {

        return [0, 1, 2, 2]

      } else if (index == 2) {

        return [0, 3, 3, 3]

      } else if (index == 3) {

        return [3, 0, 3, 3]

      } else if (index == 4) {

        return [4, 3, 2, 2]

      } else {

        return [5, 5, 1, 1]

      }

    }

  }

  @Builder

  tabBuilder(index: number, name: string) {

    Column() {

      Text(name)

        .fontColor(this.currentIndex === index ? this.selectedFontColor : this.fontColor)

        .fontSize(16)

        .fontWeight(this.currentIndex === index ? 500 : 400)

        .lineHeight(22)

        .margin({ top: 17, bottom: 7 })

      Divider()

        .strokeWidth(2)

        .color('#007DFF')

        .opacity(this.currentIndex === index ? 1 : 0)

    }.width('100%')

  }

  build() {

    Column() {

      Button('tabs停止滚动并存储位置')

        .width(100).height(100)

        .onClick(()=>{

          AppStorage.setOrCreate('this.currentIndex', this.currentIndex); //记录切换的tabs中的index, 因为这里index === 1为例 记录滚动偏移量,可以this.currentIndex设置为1

          AppStorage.setOrCreate('this.curScrollOffset1', this.scroller1.currentOffset().yOffset); // 以index === 1为例 记录滚动偏移量

        })

      Button('点击滚动到之前的位置')

        .width(100).height(100)

        .onClick(()=>{

          this.currentIndex = Number(AppStorage.get('this.currentIndex')) // 获取记录切换的tabs中的index

          this.curScrollOffset1 = Number(AppStorage.get('this.curScrollOffset1')) //获取 以index === 1为例 记录滚动偏移量

          this.scroller.scrollTo({ xOffset: 0, yOffset: this.curScrollOffset1, animation: { duration: 100, curve: Curve.Ease } }) //由于只能上下移动,所以改变yOffset即可

        })

      Tabs({ barPosition: BarPosition.Start, index: this.currentIndex, controller: this.controller }) {

        TabContent() {

          Grid(this.scroller) {

            ForEach(this.numbers1, (day: string) => {

              ForEach(this.numbers2, (day: string) => {

                GridItem() {

                  Text(day)

                    .fontSize(16)

                    .backgroundColor(0xF9CF93)

                    .width('100%')

                    .height('100%')

                    .textAlign(TextAlign.Center)

                }

              }, (day: string) => day)

            }, (day: string) => day)

          }

          .columnsTemplate('1fr 1fr 1fr 1fr 1fr')

          .columnsGap(10)

          .rowsGap(10)

          .width('100%')

          .height('100%')

          .backgroundColor('#ffffed00')

        }

        .tabBar(this.tabBuilder(0, 'green'))

        TabContent() {

          Grid(this.scroller1) {

            ForEach(this.numbers1, (day: string) => {

              ForEach(this.numbers2, (day: string) => {

                GridItem() {

                  Text(day)

                    .fontSize(16)

                    .backgroundColor(0xF9CF93)

                    .width('100%')

                    .height('100%')

                    .textAlign(TextAlign.Center)

                }

              }, (day: string) => day)

            }, (day: string) => day)

          }

          .columnsTemplate('1fr 1fr 1fr 1fr 1fr')

          .columnsGap(10)

          .rowsGap(10)

          .width('100%')

          .height('100%')

          .backgroundColor('#00ef2323')

        }

        .tabBar(this.tabBuilder(1, 'blue'))

      }

      .vertical(false)

      .barMode(BarMode.Fixed)

      .barWidth(360)

      .barHeight(56)

      .animationDuration(400)

      .onChange((index: number) => {

        if(index === 0){

          this.scroller.scrollTo({ xOffset: 0, yOffset: 0, animation: { duration: 100, curve: Curve.Ease } }) // index切换时,数据滚动到顶部

        }else{

          this.scroller1.scrollTo({ xOffset: 0, yOffset: 0, animation: { duration: 100, curve: Curve.Ease } }) // 如果想验证index === 2的偏移量是否正确,可以去掉此段代码,记录偏移量

        }

        this.currentIndex = index

        console.log("this.currentIndex"+ this.currentIndex)

      })

      .width(360)

      .height('100%')

      .margin({ top: 52 })

      .backgroundColor('#F1F3F5')

    }

    .width('100%').height('100%')

  }

}

更多关于HarmonyOS 鸿蒙Next 如何获取Grid组件中 Item距离顶部的偏移量的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next系统中,获取Grid组件中Item距离顶部的偏移量可以通过访问Grid组件的布局信息和Item的位置信息来实现。具体操作步骤如下:

  1. 获取Grid组件的Layout信息: 使用Component.getLayoutParams()方法获取Grid组件的布局参数,该参数包含组件的尺寸和位置信息。

  2. 遍历Grid中的Item: 使用Grid组件的getChildCount()getChildAt(index)方法遍历所有Item。

  3. 获取Item的顶部偏移量: 对于每个Item,使用Component.getTop()方法获取其相对于父组件(即Grid)顶部的偏移量。

  4. 累加父组件的偏移量: 如果Grid组件本身有相对于其父组件的偏移,需要累加这些偏移量以获得Item相对于整个布局顶部的最终偏移量。

示例代码(伪代码):

Grid grid = findComponentById(resourceId);
int gridTop = grid.getTop(); // Grid本身的顶部偏移量
for (int i = 0; i < grid.getChildCount(); i++) {
    Component item = grid.getChildAt(i);
    int itemTop = item.getTop(); // Item相对于Grid的顶部偏移量
    int totalTop = gridTop + itemTop; // Item相对于整个布局的顶部偏移量
    // 处理totalTop,例如存储或输出
}

注意:上述示例中的方法调用是基于组件的通用API,并非特定于鸿蒙系统的API,但原理相同。如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部