HarmonyOS 鸿蒙Next List滚动切换问题

发布于 1周前 作者 sinazl 最后一次编辑是 5天前 来自 鸿蒙OS

HarmonyOS 鸿蒙Next List滚动切换问题

List使用过程中遇见个问题,当List滚动到最上面一栏时,将其滚动使能关闭。然后又想向上滚动时,将滚动使能打开,总是第一次上滑不起作用,第二次才起作用,想问下有什么解决办法吗?具体代码如下:

具体需求是:当List所在的布局达到一定高度后,使其滚动打开,可以实现内部List的滚动。当List的滚动达到最上面一行时,将其滚动关闭。为了如果下滑可以将List所在的布局往回收起。但是如果想向上滑动时,List可以实现滚动。

import { SlideUpPanelWithGesture } from './SlideUpPanelWithGesture';

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';

  build() {
    RelativeContainer() {
      Text("滑动界面欢迎进入")
      SlideUpPanelWithGesture().alignRules({
        bottom: { anchor: "__container__", align:VerticalAlign.Bottom},
      });
    }.backgroundColor(0xf0f0f0)
    .height('100%')
    .width('100%')
  }
}

import { display } from "@kit.ArkUI";


const MIN_HEIGHT: number = 250; // Minimum height (unit: vp)
const MAX_HEIGHT: number = 650; // Maximum height (unit: vp)
const ADJUST_STEP: number = 10; // Height adjustment step
const VELOCITY_THRESHOLD: number = 0.5; // Velocity threshold to filter minor movements

@Component
export struct SlideUpPanelWithGesture {
  TAG: string = "SlideUpPanelWithGesture";
  @State private boxHeight: number = MIN_HEIGHT; // Current height of the panel
  @State private isMaxHeight: boolean = false; // Whether the panel is at max height
  private isListAtTop: boolean = true; // Whether the List is scrolled to the top
  private isFirstItemVisible: boolean = false; // Whether the first item in the List is visible
  @State private enableScroll: boolean = false; // Whether scrolling is enabled for the List

  calculateRemainingHeight(): number {
    return px2vp(display.getDefaultDisplaySync().height) - this.boxHeight;
  }

  build() {
    RelativeContainer() {
      this.buildShade();
      this.buildList();
    }
    .backgroundColor(Color.Pink)
    .width("100%")
    .height("100%");
  }

  @Builder
  private buildShade() {
    if (this.isMaxHeight) {
      RelativeContainer() {
        Rect({ width: '20%', height: 8 })
          .radius(5)
          .fill("#ffffff")
          .margin({ top: this.calculateRemainingHeight() - 80 })
          .alignRules({ middle: { anchor: "__container__", align: HorizontalAlign.Center } });
      }
      .height(this.calculateRemainingHeight())
      .width("100%")
      .backgroundColor("rgba(0, 0, 0, 0.3)");
    }
  }

  @Builder
  private buildList() {
    RelativeContainer() {
      List() {
        this.buildDragIndicator();
        this.buildListContent();
      }
      .onScrollIndex((start, end, center) => this.handleScrollIndex(start, end, center))
      .enableScrollInteraction(this.enableScroll)
      .onWillScroll((scrollOffset) => this.handleScroll(scrollOffset))
      .alignListItem(ListItemAlign.Center)
      .scrollBar(BarState.Off)
      .gesture(
        PanGesture({ direction: PanDirection.Vertical })
          .onActionUpdate((event) => this.handlePanGesture(event))
      )
      .backgroundColor("#ffffff")
      .width("100%")
      .height(this.boxHeight)
      .borderRadius({ topLeft: 20, topRight: 20 })
      .alignRules({
        bottom: { anchor: "__container__", align: VerticalAlign.Bottom },
        middle: { anchor: "__container__", align: HorizontalAlign.Center }
      });
    }
  }

  @Builder
  private buildDragIndicator() {
    ListItem() {
      Rect({ width: '20%', height: 8 })
        .radius(5)
        .fill("#ff0000");
    }
    .visibility(this.isMaxHeight ? Visibility.None : Visibility.Visible)
    .margin({ bottom: 10, top: 10 });
  }

  @Builder
  private buildListContent() {
    ListItem() {
      Text(`Row 1`).fontSize(18).margin({ top: 20 });
    }

    ListItemGroup() {
      ForEach(this.createArray(30), (item: number) => {
        ListItem() {
          Text(`Content Row ${item}`)
            .fontSize(18)
            .padding(10);
        };
      });
    }
  }

  private handlePanGesture(event: GestureEvent) {
    console.info(this.TAG,
      `PanGesture update: isMaxHeight=${this.isMaxHeight}, velocityY=${event.velocityY}, isListAtTop=${this.isListAtTop}, enableScroll=${this.enableScroll}`);
    if (Math.abs(event.velocityY) <= VELOCITY_THRESHOLD) {
      console.info(this.TAG, "Ignored minor movement");
      return;
    }

    if (this.isMaxHeight) {
      if (this.isListAtTop && event.velocityY > 0) {
        this.enableScroll = false;
        this.adjustBoxHeight(-ADJUST_STEP);
      } else {
        this.enableScroll = true;
      }
    } else {
      this.adjustBoxHeight(event.velocityY > 0 ? -ADJUST_STEP : ADJUST_STEP);
    }
  }

  private handleScroll(scrollOffset: number) {
    this.isListAtTop = scrollOffset <= 0.2; // Allow small deviation
    console.info(this.TAG,
      `Scroll event: isListAtTop=${this.isListAtTop}, scrollOffset=${scrollOffset}, isFirstItemVisible=${this.isFirstItemVisible}}`);
    if (this.isListAtTop && this.isFirstItemVisible) {
      this.enableScroll = false;
    }
  }

  private handleScrollIndex(start: number, end: number, center: number) {
    console.info(this.TAG, `ScrollIndex: start=${start}, end=${end}, center=${center}`);
    this.isFirstItemVisible = start === 0;
  }

  private adjustBoxHeight(offset: number) {
    const newHeight = Math.min(Math.max(this.boxHeight + offset, MIN_HEIGHT), MAX_HEIGHT);
    this.boxHeight = newHeight;
    this.isMaxHeight = newHeight === MAX_HEIGHT;
    console.info(this.TAG, `Box height adjusted: ${this.boxHeight}, isMaxHeight=${this.isMaxHeight}`);
  }

  private createArray(length: number): number[] {
    const array: number[] = [];
    for (let i = 0; i < length; i++) {
      array.push(i);
    }
    return array;
  }
}


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

4 回复

handleScroll方法中this.enableScroll变为false的条件有问题,改为:

  private handleScroll(scrollOffset: number) {
    this.isListAtTop = scrollOffset <= 0.2; // Allow small deviation
    console.info(this.TAG,
      `Scroll event: isListAtTop=${this.isListAtTop}, scrollOffset=${scrollOffset}, isFirstItemVisible=${this.isFirstItemVisible}}`);
    if (scrollOffset===0 && this.isFirstItemVisible) { // 在List顶部下滑(scrollOffset为0)且顶部红条可见时,List设为不可滚动
      this.enableScroll = false;
 isFirstItemVisible:${this.isFirstItemVisible}`)
    }
  }

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


看了下你的需求,其实用List组件的.nestedScroll()方法即可实现。

@Entry
@Component
struct Index {
  nums: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9]

  build() {
    Scroll() {
      Column() {
        Text('占位1').fontSize(50).fontColor(Color.Red)
        Text('占位2').fontSize(50).fontColor(Color.Red)
        Text('占位3').fontSize(50).fontColor(Color.Red)
        List() {
          ForEach(this.nums, (num: number) => {
            ListItem() {
              Text('ListItem' + num).fontSize(60).fontColor(Color.Green)
            }
          })
        }
        .height('60%')
        .edgeEffect(EdgeEffect.None)
        .nestedScroll({
          scrollForward: NestedScrollMode.SELF_FIRST,
          scrollBackward: NestedScrollMode.SELF_FIRST
        })

        Text('占位4').fontSize(50).fontColor(Color.Blue)
        Text('占位5').fontSize(50).fontColor(Color.Blue)
        Text('占位6').fontSize(50).fontColor(Color.Blue)
        Text('占位7').fontSize(50).fontColor(Color.Blue)
        Text('占位8').fontSize(50).fontColor(Color.Blue)
      }
    }
    .height('100%')
    .width('100%')
  }
}

cke_1575.gif

和你提供的demo不太一样,你这个demo是两个滚动的来回切换。我这个需求是内部滚动和外部滑动高度的切换。

针对HarmonyOS鸿蒙Next List滚动切换问题,以下是一些可能的解决方案及信息:

在HarmonyOS系统中,Next List组件的滚动切换功能通常依赖于系统的动画效果和列表数据的动态加载。若遇到滚动切换不流畅或异常,可首先检查以下几点:

  1. 数据加载:确保列表数据在滚动过程中是实时加载的,且加载速度足够快,避免卡顿。

  2. 动画效果:检查Next List的滚动动画设置,确保动画效果与设备性能相匹配,避免过度消耗资源。

  3. 组件版本:确认所使用的Next List组件版本是否为最新,旧版本可能存在已知的滚动切换问题。

  4. 系统兼容性:测试在不同的HarmonyOS设备上滚动切换的效果,以排除设备或系统版本差异导致的问题。

  5. 代码审查:仔细检查与Next List滚动切换相关的代码,确保没有逻辑错误或不当的数据处理。

若以上方法均未能解决问题,可能是系统或组件本身的bug。此时,建议记录详细的复现步骤和日志信息,以便进一步分析。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部