HarmonyOS 仿AppBarLayout吸附使用Scroll滚动到顶时出现抖动问题

通过onScroll移动scroll上层的组件,实现吸附效果,在滚动到顶部的场景下出现抖动问题,使用onWillScroll,onDidScroll问题更明显

HarmonyOS
4h前
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
aquaa

出现抖动是因为回到顶层使用了动画,然后Text没有动画效果,才会出现这样,这个目前吸顶的效果不建议在scroll的时候margin,可以参考下这个demo:

enum ScrollPosition {
  start,
  center,
  end
}

class ItemClass {
  content: string = '';
  color: Color = Color.White;
}

@Entry
@Component
struct NestedScrollDemo {
  @State listPosition: number = ScrollPosition.start; // 0代表滚动到List顶部,1代表中间值,2代表滚动到List底部。
  @State scrollPosition: number = ScrollPosition.start; // 0代表滚动到页面顶部,1代表中间值,2代表滚动到页面底部。
  @State showTitle: boolean = false;
  @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 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
  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)")
          .backgroundColor('#F1F3F5')
        }
      }
      .scrollBar(BarState.Off)
      .width("100%")
      .height("100%")
      .onScroll((xOffset: number, yOffset: number) => {
        this.currentYOffset = this.scrollerForScroll.currentOffset().yOffset;

        // 非(页面在顶部或页面在底部),则页面在中间
        if (!((this.scrollPosition == ScrollPosition.start && yOffset < 0)
          || (this.scrollPosition == ScrollPosition.end && yOffset > 0))) {
          this.scrollPosition = ScrollPosition.center
        }
      })
      .onScrollEdge((side: Edge) => {
        if (side == Edge.Top) {
          // 页面在顶部
          this.scrollPosition = ScrollPosition.start
        } else if (side == Edge.Bottom) {
          // 页面在底部
          this.scrollPosition = ScrollPosition.end
        }
      })
      .onScrollFrameBegin(offset => {
        if (this.scrollPosition == ScrollPosition.end) {
          return { offsetRemain: 0 };
        } else {
          return { offsetRemain: offset };
        }
      })
    }
    .width('100%')
    .height('100%')
    .backgroundColor(0xDCDCDC)
  }
}
分享
微博
QQ
微信
回复
3h前
相关问题
HarmonyOS Scroll组件滚动问题
548浏览 • 1回复 待解决
Web组件怎么知道滚动到顶部了
845浏览 • 1回复 待解决
仿射变换后列表滑动问题
274浏览 • 1回复 待解决
HarmonyOS scroll动问题
451浏览 • 1回复 待解决
Scroll中点击某一个层图片移动到顶
832浏览 • 1回复 待解决
HarmonyOS Tabs组件的Tab栏滚动问题
531浏览 • 1回复 待解决
Grid嵌套滚动问题有知道的吗?
2641浏览 • 1回复 待解决
HarmonyOS Scroll组件使用问题
395浏览 • 1回复 待解决
Scroll初始自动滚动一段距离
894浏览 • 1回复 待解决
HarmonyOS scroll和list滚动冲突
394浏览 • 1回复 待解决
HarmonyOS LongPressGesture手势移动问题
471浏览 • 1回复 待解决
HarmonyOS 悬浮按钮拖动问题
342浏览 • 1回复 待解决
HarmonyOS swiper如何滚动到任意页面?
461浏览 • 1回复 待解决
HarmonyOS Grid组件子项拖动问题
175浏览 • 1回复 待解决
list组件无法滚动到底部
1270浏览 • 1回复 待解决
HarmonyOS 嵌套滑动问题
337浏览 • 1回复 待解决
HarmonyOS list滑动问题
809浏览 • 1回复 待解决
HarmonyOS Slider滑动问题
344浏览 • 1回复 待解决
怎么判断webview滚动到最下方?
427浏览 • 2回复 待解决