嵌套滑动 HarmonyOS 鸿蒙Next

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

嵌套滑动 HarmonyOS 鸿蒙Next 嵌套滑动处理,除了.nestedScroll({ scrollForward: NestedScrollMode.PARENT_FIRST, scrollBackward: NestedScrollMode.SELF_FIRST })

这种方式,还有其他方式吗?

目前遇到的问题是,外层是Scroll,里层是Swiper,Swiper里层是List,给List设置

.nestedScroll({ scrollForward: NestedScrollMode.PARENT_FIRST, scrollBackward: NestedScrollMode.SELF_FIRST })

这时候嵌套滑动处理正常

需求增加下拉刷新和上拉加载,给List外层再套一层自定义的下拉刷新和上拉加载布局后,嵌套滑动处理不能工作了。


更多关于嵌套滑动 HarmonyOS 鸿蒙Next的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

嵌套滑动+下拉刷新可以参考以下demo:

@Entry
@Component
struct WeiboPersonPage {
  @State currentTitle: string = '顶部模块'
  @State data: Array<string> = [];
  @State data2: Array<string> = [];
  mainScroller: Scroller = new Scroller();
  tags: Array<string> = ['标签1', '标签2', '标签3', '标签4'];
  tagScrollers: Array<Scroller> = []; //每个scroller对应一个标签
  @State hideNavBar: boolean = true;
  @State hideLoadingView: boolean = true;
  @State mainListCanScroll: boolean = true;
  @State currentPageHeight: number = 0;
  @State currentPageWidth: number = 0;
  @State progress: number = 0; //0-10
  @State isRefreshing: boolean = false;
  panOption: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.Up | PanDirection.Down });
  @State isLoadingFromBottom: boolean = false;

  aboutToAppear() {
    for (let i = 0; i < this.tags.length; i++) {
      let tagScroller = new Scroller();
      this.tagScrollers.push(tagScroller);
    }
    for (let i = 0; i < 2; i++) {
      this.data.push(`自定义header内容`)
    }
    for (let i = 0; i < 50; i++) {
      this.data2.push(`Hello ${i}`)
    }
  }

  build() {
    Column() {
      Navigation() {
        Stack({ alignContent: Alignment.TopStart }) {
          this.mainListView(this.mainScroller, this.tagScrollers)
          Progress({ value: this.progress, total: 10, type: ProgressType.Ring })
            .width(20)
            .color(Color.Orange)
            .style({
              strokeWidth: 20,
              status: this.isRefreshing == true ? ProgressStatus.LOADING : ProgressStatus.PROGRESSING,
              enableSmoothEffect: true,
              enableScanEffect: true
            })
            .backgroundColor(Color.Yellow)
            .visibility((this.hideLoadingView == false || this.isRefreshing) ? Visibility.Visible : Visibility.Hidden)
            .margin({ left: this.currentPageWidth - 23 - 20 })
          Button({ type: ButtonType.Normal, stateEffect: true }) {
            Image($r('app.media.icon')).width(40).height(40)
          }
          .margin({ left: 23 })
          .backgroundColor(Color.Blue)
          .onClick(() => {})
          .visibility(this.hideNavBar == false ? Visibility.Hidden : Visibility.Visible)
        }
      }
      .backgroundColor(Color.White)
      .title(this.NavigationTitle)
      .margin({
        top: $r('app.media.icon')
      })
      .width('100%')
      .titleMode(NavigationTitleMode.Mini)
      .hideBackButton(false)
      .zIndex(1)
      .mode(NavigationMode.Auto)
      .hideTitleBar(this.hideNavBar)
      .parallelGesture(
        PanGesture(this.panOption)
          .onActionStart((event?: GestureEvent) => {})
          .onActionUpdate((event?: GestureEvent) => {})
          .onActionEnd(() => {
            if (this.progress >= 10) {
              this.isRefreshing = true;
              console.info('开始刷新========1')
              setTimeout(() => {
                this.isRefreshing = false;
                this.data2.unshift('1111');
              }, 2000);
            } else {
              this.isRefreshing = false;
              console.info('取消刷新========1')
            }
          })
      )
    }
    .width('100%')
    .backgroundColor($r('app.media.icon'))
    .height('100%')
    .onAreaChange((oldValue: Area, newValue: Area) => {
      console.info('onAreaChange:' + newValue.height.toString());
      this.currentPageHeight = Math.round(newValue.height as number);
      this.currentPageWidth = Math.round(newValue.width as number);
    })
  }

  //自定义导航
  @Builder
  NavigationTitle() {
    Column() {
      Text(this.currentTitle)
        .fontColor('#182431')
        .fontSize(18)
        .fontWeight(600)
        .backgroundColor(Color.Yellow)
        .height(56)
    }
    .width('67%')
    .height(56)
    .backgroundColor(Color.Grey)
  }

  @Builder
  listView(scroller: Scroller) {
    List({ space: 0, scroller: scroller }) {
      ForEach(this.data2, (item: string, index?: number) => {
        ListItem() {
          if (this.isLoadingFromBottom) {
            if (index == this.data2.length - 1) {
              Row() {
                Text('加载中...').fontSize(50)
                Progress({ value: 0, total: 20, type: ProgressType.Ring })
                  .width(20)
                  .color(Color.Orange)
                  .style({
                    strokeWidth: 20,
                    status: ProgressStatus.LOADING,
                    enableSmoothEffect: true,
                    enableScanEffect: true
                  })
                  .backgroundColor(Color.Red)
              }.margin({ left: 10, right: 10 })
            } else {
              Row() {
                Text(item).fontSize(50).width('100%')
              }.margin({ left: 10, right: 10 })
            }
          } else {
            Row() {
              Text(item).fontSize(50).width('100%')
            }.margin({ left: 10, right: 10 })
          }
        }
        .backgroundColor(Color.White)
      }, (item: string) => item)
    }
    .cachedCount(5)
    .divider({ strokeWidth: 1, color: 0x222222 })
    .edgeEffect(EdgeEffect.None)
    .enableScrollInteraction(this.mainListCanScroll ? false : true)
    .onScroll((scrollOffset: number, scrollState: ScrollState) => {
      if (scroller.currentOffset().yOffset == 0) {
        this.mainListCanScroll = true
      } else {
        this.mainListCanScroll = false
      }
    })
    .onReachEnd(() => {
      if (this.isLoadingFromBottom == true) {
        return;
      }
      this.isLoadingFromBottom = true;
      this.data2.push('占位数据');
      setTimeout(() => {
        console.info('加载结束=====1')
        this.isLoadingFromBottom = false;
        this.data2.pop();
        this.data2.push('新的数据' + this.data2.length);
        this.data2.push('新的数据' + this.data2.length);
        this.data2.push('新的数据' + this.data2.length);
        this.data2.push('新的数据' + this.data2.length);
        this.data2.push('新的数据' + this.data2.length);
        this.data2.push('新的数据' + this.data2.length);
        this.data2.push('新的数据' + this.data2.length);
        this.data2.push('新的数据' + this.data2.length);
        this.data2.push('新的数据' + this.data2.length);
        this.data2.push('新的数据' + this.data2.length);
        this.data2.push('新的数据' + this.data2.length);
        this.data2.push('新的数据' + this.data2.length);
        this.data2.push('新的数据' + this.data2.length);
        this.data2.push('新的数据' + this.data2.length);
        this.data2.push('新的数据' + this.data2.length);
        this.data2.push('新的数据' + this.data2.length);
        this.data2.push('新的数据' + this.data2.length);
        this.data2.push('新的数据' + this.data2.length);
      }, 3000);
    })
  }

  @Builder
  mainListView(mainScroller: Scroller, tagScrollers: Array<Scroller>) {
    List({ space: 0, scroller: mainScroller }) {
      ForEach(this.data, (item: string, index?: number) => {

        if (index == 0) {
          ListItem() {
            Row() {
              Text(item).fontSize(50).width('100%')
            }.margin({ left: 10, right: 10 })
          }
          .height(400) 
          .backgroundColor(Color.Red)
        } else {
          ListItem() {
            Tabs({ barPosition: BarPosition.Start }) {
              TabContent() {
                this.listView(tagScrollers[0])
              }
              .tabBar('首页')

              TabContent() {
                this.listView(tagScrollers[1])
              }
              .tabBar('推荐')

              TabContent() {
                this.listView(tagScrollers[2])
              }
              .tabBar('发现')

              TabContent() {
                this.listView(tagScrollers[3])
              }
              .tabBar("我的")
            }
          }
          .height(this.currentPageHeight - 56 - 40)
          .backgroundColor(Color.Green)
        }
      }, (item: string) => item)
    }
    .cachedCount(2)
    .backgroundColor(Color.White)
    .divider({
      strokeWidth: 1,
      startMargin: '3.5%',
      endMargin: '2%',
      color: '#f2f2f2'
    })
    .edgeEffect(EdgeEffect.None) 
    .divider({ strokeWidth: 1, color: 0x222222 })
    .edgeEffect(EdgeEffect.Spring)
    .scrollBar(BarState.Off)
    .enableScrollInteraction(this.mainListCanScroll)
    .onScroll((scrollOffset: number, scrollState: ScrollState) => {
      console.info('offset1:' + this.mainScroller.currentOffset().yOffset);
      let currentOffsetY = Math.round(this.mainScroller.currentOffset().yOffset);
      if (currentOffsetY > 100) {
        this.hideNavBar = false
      } else {
        this.hideNavBar = true
      }
      if (currentOffsetY == 0) {
        this.mainListCanScroll = true
      } else {
        if (currentOffsetY >= 400) {
          this.mainListCanScroll = false
        } else {
          this.mainListCanScroll = true
        }
      }
      if (currentOffsetY >= 0) {
        this.hideLoadingView = true
      } else {
        this.hideLoadingView = false
      }
      this.progress = currentOffsetY / 80 * (-10);
    })
    .onReachStart(() => {
      console.info('到最上面了========1')
    })
    .onReachEnd(() => {
      console.info('到最底部了========1')
    })
  }
}

更多关于嵌套滑动 HarmonyOS 鸿蒙Next的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


针对“嵌套滑动 HarmonyOS 鸿蒙Next”的问题,以下是一个简洁且专业的回答:

在HarmonyOS鸿蒙Next系统中,嵌套滑动功能的实现主要依赖于其独特的UI框架和组件系统。为了实现嵌套滑动,开发者需要合理利用鸿蒙提供的滑动组件,如Scroll、NestedScroll等,并正确设置它们的属性与事件监听。

鸿蒙系统的嵌套滑动机制允许在一个滚动视图内再嵌套另一个滚动视图,同时保持两者之间的滑动协调。这通常涉及到滑动冲突的解决,即当两个滚动视图同时检测到滑动操作时,系统需要决定哪个视图应该响应滑动。

在实现嵌套滑动时,开发者需要注意以下几点:

  • 确保外层滚动视图和内层滚动视图的滚动方向合理设置,避免不必要的滑动冲突。
  • 利用鸿蒙提供的API,如setNestedScrollingEnabled等,来启用或禁用嵌套滑动功能。
  • 合理处理滑动事件,确保在不同滑动状态下,用户能够获得流畅且符合预期的操作体验。

如果开发者在实现嵌套滑动功能时遇到具体问题,建议检查滚动组件的属性设置、事件监听以及滑动冲突的解决策略。如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部