HarmonyOS鸿蒙Next中圆形列表渐隐效果适配

HarmonyOS鸿蒙Next中圆形列表渐隐效果适配 在使用scale对组件进行缩小后,缩小前的位置会仍然占有,导致循环列表的每一项都会有不均匀的间隙,无法紧挨到一起,如果直接对组件的宽高进行控制的话,组件里面的字又不会跟着一起缩小,而且有抖动,体验不好。

interface ScaleRange {
  MIN: number,
  MAX: number
}

interface ScaleZone {
  TOP: number[], // 顶部渐隐区
  CENTER: number[], // 中心区域
  BOTTOM: number[] // 底部渐隐区
}

@Entry
@Component
struct Index {
  @State yOffset: number = 0
  @State maxScrollOffset: number = 0
  @State viewportHeight: number = 0
  @State listItemScale: number[] = []
  private listScroller: ListScroller = new ListScroller()
  @State
  array: Array<string> =
    ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20',
      '21', '22', '23', '24', '25', '26', '27', '28', '29', '30']
  // 在组件顶部新增常量
  private readonly SCALE_RANGE: ScaleRange = {
    MIN: 0.5, // 渐隐最小比例
    MAX: 1.0 // 最大比例
  };
  private readonly SCROLL_ZONE: ScaleZone = {
    TOP: [0, 86.5], // 顶部渐隐区(0-86.5)
    CENTER: [86.5, 146.5], // 中心区域
    BOTTOM: [146.5, 233]   // 底部渐隐区(146.5-233)
  };

  build() {
      List({
        scroller: this.listScroller,
      }) {
        ListItem() {
          Column() {
            Text('12:00')
              .fontColor(Color.White)
            Blank().height(8)
            Text('今日状态')
              .fontSize(17)
              .fontWeight(FontWeight.Bold)
              .fontColor('#ADA7F6')
          }.padding({
            top: 10, bottom: 10
          })
        }

        ListItem()
        .width('100%')
        .height(82)
        .backgroundColor('#1FFFFFFF')
        .borderRadius(41)

        ForEach(this.array, (item: string, index: number) => {
          ListItem() {
            // 列表项内容...
            CommonListItem({
              icon: $r('sys.media.return_home_fill'),
              text: '项目' + item,
              slot: calorieLeftDataItem,
              slotValue1: 150,
            })
          }
          .width('100%')
          .height(60)
          .scale({ x: this.listItemScale[index], y: this.listItemScale[index] })
          .onAreaChange((oldValue, newValue) => {
            const ITEM_HEIGHT = newValue.height as number; // 列表项原始高度
            const childCenter = (newValue.position.y as number) + ITEM_HEIGHT / 2;
            console.log(`项目${index + 1}: ` + (newValue.position.y as number))

            let scale = this.SCALE_RANGE.MAX;

            // 处理顶部区域(0-86.5)
            if (childCenter <= this.SCROLL_ZONE.TOP[1]) {
              const start = this.SCROLL_ZONE.TOP[0];
              const end = this.SCROLL_ZONE.TOP[1];
              const progress = Math.min(1, (childCenter - start) / (end - start));

              // 缩放比例从0.5到1.0
              scale = this.SCALE_RANGE.MIN + (this.SCALE_RANGE.MAX - this.SCALE_RANGE.MIN) * progress;

            }
            // 处理底部区域(146.5-233)
            else if (childCenter >= this.SCROLL_ZONE.BOTTOM[0]) {
              const start = this.SCROLL_ZONE.BOTTOM[0];
              const end = this.SCROLL_ZONE.BOTTOM[1];
              const progress = Math.min(1, (childCenter - start) / (end - start));

              // 缩放比例从1.0到0.5
              scale = this.SCALE_RANGE.MAX - (this.SCALE_RANGE.MAX - this.SCALE_RANGE.MIN) * progress;

            }
            // 中心区域(86.5-146.5)保持最大值
            else {
              scale = this.SCALE_RANGE.MAX;
            }
            this.listItemScale[index] = Math.min(
              this.SCALE_RANGE.MAX,
              Math.max(this.SCALE_RANGE.MIN, scale)
            );
          })

        })
      }
      .height('100%')
      .width('100%')
      .padding({ left: 4, right: 4 })
      .scrollSnapAlign(this.yOffset > 0 ? ScrollSnapAlign.CENTER : ScrollSnapAlign.START)
      .scrollBar(BarState.Off)
      .alignListItem(ListItemAlign.Center)
      .defaultFocus(true)
      .onAreaChange((oldValue, newValue) => {
        if (newValue.height > 0) {
          this.viewportHeight = newValue.height as number
          const contentHeight = 65.5 + this.array.length * 60 + 90
          this.maxScrollOffset = Math.max(0, contentHeight - this.viewportHeight)
        }
        console.info('onAreaChange: ' + JSON.stringify(vp2px(newValue.height as number)))
      })
      .onWillScroll(() => {
        this.yOffset = this.listScroller.currentOffset().yOffset
      })
  }
}

@Component
export struct CommonListItem {
  @Builder
  CustomBuildFunction() {
  }

  icon?: Resource
  text?: string
  slotValue1?: number | string
  slotValue2?: number | undefined
  @BuilderParam
  slot: (value1: number | string, value2?: number | undefined) => void = this.CustomBuildFunction

  build() {
    Row({ space: 4 }) {
      Image(this.icon)
        .width(20)
        .height(20)
        .fillColor(Color.White)
      Text(this.text)
        .fontColor(Color.White)
        .fontSize(13)
        .fontWeight(600)
        .lineHeight(19)
        .layoutWeight(1)
        .textAlign(TextAlign.Start)
      if (!this.slotValue2) {
        this.slot(this.slotValue1!)
      } else {
        this.slot(this.slotValue1!, this.slotValue2!)
      }
    }
    .width('100%')
    .height('100%')
    .padding({
      left: 11,
      right: 11,
      // top: 10,
      // bottom: 10
    })
    .backgroundColor('#1FFFFFFF')
    .borderRadius(30)
  }
}

@Builder
export function calorieLeftDataItem(value1: number | string) {
  Text() {
    Span(`${value1 || '--'}`)
      .fontColor(Color.White)
      .fontSize(15)
      .fontWeight(700)
    Span('xxxx')
      .fontColor(Color.White)
      .fontSize(10)
      .fontWeight(600)
  }
}

更多关于HarmonyOS鸿蒙Next中圆形列表渐隐效果适配的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

在HarmonyOS鸿蒙Next中实现圆形列表渐隐效果,可以通过使用ArkUI框架中的组件和动画特性来完成。首先,使用List组件创建圆形列表布局,结合FlexGrid实现圆形排列。接着,通过CanvasShape组件绘制圆形,并设置渐隐效果。

渐隐效果可以通过Animation组件实现。定义@State变量控制透明度,使用animateTo方法在列表滚动时动态改变透明度。例如:

@State opacity: number = 1.0;

animateTo({ duration: 500 }, () => {
  this.opacity = 0.0;
});

ListonScroll事件中触发动画,根据滚动位置调整透明度。确保渐隐效果平滑过渡,避免卡顿。

此外,可以使用LinearGradientRadialGradient设置渐变色,增强视觉层次感。通过合理布局和动画参数,实现流畅的圆形列表渐隐效果。

更多关于HarmonyOS鸿蒙Next中圆形列表渐隐效果适配的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中实现圆形列表的渐隐效果,可以通过自定义RecyclerViewItemDecoration来实现。首先,在onDrawOver方法中绘制渐隐效果,使用LinearGradientRadialGradient创建渐变,结合Canvas绘制。然后,在getItemOffsets中设置列表项的间距,确保渐隐效果与列表项布局协调。最后,通过RecyclerView.addItemDecoration将自定义的ItemDecoration应用到列表中。此方法适用于需要动态调整渐隐效果的场景,确保UI的流畅性和美观性。

回到顶部