HarmonyOS 鸿蒙Next 置顶粘贴效果除了list的sticky还有别的方案吗?

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

HarmonyOS 鸿蒙Next 置顶粘贴效果除了list的sticky还有别的方案吗?

 置顶粘贴效果出了list的sticky 还有别的方案吗? 

2 回复

可以使用偏移量通过代码逻辑来实现,以下是简单的demo:

enum ScrollPosition {

  start,

  center,

  end

}

class ItemClass {

  content: string = '';

  color: Color = Color.White;

}

[@Entry](/user/Entry)

[@Component](/user/Component)

struct NestedScroll {

  [@State](/user/State) listPosition: number = ScrollPosition.start; // 0代表滚动到List顶部,1代表中间值,2代表滚动到List底部。

  [@State](/user/State) scrollPosition: number = ScrollPosition.start; // 0代表滚动到页面顶部,1代表中间值,2代表滚动到页面底部。

  [@State](/user/State) showTitle: boolean = false;

  [@State](/user/State) currentYOffset: number = 0;

  private arr: ItemClass[] = [];

  private colorArr: Color[] = [Color.White, Color.Blue, Color.Brown, Color.Green, Color.Gray];

  private scrollerForScroll: Scroller = new Scroller();

  private scrollerForList: Scroller = new Scroller();

  private scrollerForTitle: Scroller = new Scroller();

  [@State](/user/State) currentIndex: number = 0;

  aboutToAppear() {

    for(let i = 0; i < 6; i++) {

      let data: ItemClass = {

        content: i.toString(),

        color: this.colorArr[i % 5]

      }

      this.arr.push(data);

    }

  }

  [@Builder](/user/Builder) myBuilder() {

    Row() {

      List({ space: 2, initialIndex: 0, scroller: this.scrollerForTitle }) {

        ForEach(this.arr, (item: ItemClass, index) => {

          ListItem() {

            Column() {

              Text(item.content);

              Divider()

                .color('#000000')

                .strokeWidth(5)

                .visibility(index == this.currentIndex ? Visibility.Visible : Visibility.Hidden)

            }

            .width('25%')

            .height(50)

            .onClick(() => {

              this.scrollerForList.scrollToIndex(index)

              this.scrollerForScroll.scrollEdge(Edge.Bottom)

            })

          }

        })

      }

      .listDirection(Axis.Horizontal)

      .scrollBar(BarState.Off)

    }

    .backgroundColor('#ffe2d0d0')

    .alignItems(VerticalAlign.Center)

  }

build() {

    Stack({ alignContent: Alignment.Top }) {

      Scroll(this.scrollerForScroll) {

        Column() {

          Image($r('app.media.app_icon'))

            .width("100%")

            .height("40%")

          this.myBuilder();

          List({ space: 10, scroller: this.scrollerForList }) {

            ForEach(this.arr, (item: ItemClass, index) => {

              ListItem() {

                Column() {

                  Text(item.content)

                  //添加其他内容

                }

                .width('100%')

                .height(500)

                .backgroundColor(item.color)

              }.width("100%").height(500)

              .onVisibleAreaChange([0.8], (isVisible) => {

                if (isVisible) {

                  this.currentIndex = index;

                  this.scrollerForTitle.scrollToIndex(this.currentIndex);

                }

              })

            }, (item: ItemClass) => item.content)

          }

          .padding({ left: 10, right: 10 })

          .width("100%")

          .edgeEffect(EdgeEffect.None)

          .scrollBar(BarState.Off)

          .onReachStart(() => {

            this.listPosition = ScrollPosition.start

          })

          .onReachEnd(() => {

            this.listPosition = ScrollPosition.end

          })

          .onScrollFrameBegin((offset: number, state: ScrollState) => {

            // 滑动到列表中间时

            if (!((this.listPosition == ScrollPosition.start && offset < 0)

              || (this.listPosition == ScrollPosition.end && offset > 0))) {

              this.listPosition = ScrollPosition.center

            }

            // 如果页面已滚动到底部,列表不在顶部或列表有正向偏移量

            if (this.scrollPosition == ScrollPosition.end

              && (this.listPosition != ScrollPosition.start || offset > 0)) {

              return { offsetRemain: offset };

            } else {

              this.scrollerForScroll.scrollBy(0, offset)

              return { offsetRemain: 0 };

            }

          })

          .width("100%")

          .height("calc(100% - 50vp)")

创建菜单时,如果普通的文本菜单不满足需求,可在bindMenu中传入CustomBuilder,创建自定义菜单。以下是简单的demo:

[@Entry](/user/Entry)

[@Component](/user/Component)

struct MenuExample {

  [@State](/user/State) listData: number[] = [0, 0, 0]

  [@Builder](/user/Builder) MenuBuilder() {

    Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {

      ForEach(this.listData, (item, index) => {

        Column() {

          Row() {

            Image($r("app.media.icon")).width(20).height(20).margin({ right: 5 })

            Text(`Menu${index + 1}`).fontSize(20)

          }

          .width('100%')

          .height(30)

          .justifyContent(FlexAlign.Center)

          .align(Alignment.Center)

          .onClick(() => {

            console.info(`Menu${index + 1} Clicked!`)

          })

          if (index != this.listData.length - 1) {

            Divider().height(10).width('80%').color('#ccc')

          }

        }.padding(5).height(40)

      })

    }.width(100)

  }

  build() {

    Column() {

      Text('click for menu')

        .fontSize(20)

        .margin({ top: 20 })

        .bindMenu(this.MenuBuilder)

    }

    .height('100%')

    .width('100%')

    .backgroundColor('#f0f0f0')

  }

}

更多关于HarmonyOS 鸿蒙Next 置顶粘贴效果除了list的sticky还有别的方案吗?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙系统中,实现置顶粘贴效果除了使用List组件的sticky属性外,还存在其他方案。一种方法是利用自定义布局和动画效果来模拟置顶粘贴的行为。

具体来说,可以通过在数据更新时动态调整目标项的位置,同时利用动画效果使该项平滑地移动到置顶位置。这种方法需要精确地控制布局参数和动画插值器,以确保置顶效果的自然和流畅。

另外,还可以考虑使用ScrollView组件结合自定义的LayoutManager来实现置顶效果。通过重写LayoutManager的滚动逻辑,可以在滚动过程中检测到目标项的位置,并在需要时将其移动到置顶位置。这种方法需要对ScrollView和LayoutManager的工作原理有较深入的理解。

值得注意的是,无论采用哪种方案,都需要对UI性能进行优化,以避免因频繁布局或动画计算而导致的卡顿现象。

如果以上方案仍无法满足需求,或实现过程中遇到具体问题,建议直接参考HarmonyOS的官方文档或示例代码,以获取更详细的实现方法和最佳实践。如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html。

回到顶部