HarmonyOS 鸿蒙Next中如何实现手风琴动画

HarmonyOS 鸿蒙Next中如何实现手风琴动画

鸿蒙如何实现手风琴动画

4 回复
@Entry
@Component
struct ShadesDemo {
  @State widths: string[] = ['20%', '20%', '20%', '20%', '20%'] // 初始宽度数组
  @State colors: number[] = [Color.Green, Color.Blue, Color.Yellow, Color.Red, Color.Orange]

  build() {
    Flex({ direction: FlexDirection.Row }) {
      ForEach(this.widths, (width: string, index) => {
        Column() {
          Image('')
            .width('100%')
            .height('100%')
            .draggable(false)
            .backgroundColor(this.colors[index])
        }
        .width(this.widths[index])
        .height(300)
        .onTouch((event: TouchEvent) => {
          // 手指离开组件时还原宽度
          if (event.type === TouchType.Up) {
            this.getUIContext().animateTo({ duration: 300, curve: Curve.Ease }, () => {
              this.widths = ['20%', '20%', '20%', '20%', '20%']
            })
          } else {
            // 手指触摸组件时触发宽度更新
            this.updateWidths(index)
          }
        })
      }, (width: string, index: number) => index.toString())
    }
  }

  private updateWidths(activeIndex: number) {
    this.getUIContext().animateTo({ duration: 300, curve: Curve.Ease }, () => {
      this.widths = this.widths.map((_, idx) =>
      idx === activeIndex ? '60%' : '10%'
      )
    })
  }
}

更多关于HarmonyOS 鸿蒙Next中如何实现手风琴动画的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


可以使用显式动画animateTo结合条件渲染if控制 ListItem内容区域的展开和收起:

@Entry
@Component
struct ListCollapseExpand {
  private arr: number[] = [0, 1, 2, 3, 4, 5, 6];
  @State isContentShow: boolean = true;
  @State selectItem: number = 0;

  build() {
    Column() {
      List({ initialIndex: 0 }) {
        ForEach(this.arr, (item: number, index: number) => {
          ListItem() {
            Column() {
              Text(item.toString())
                .height(40)
                .width('100%')
                .onClick(() => {
                  this.getUIContext().animateTo({
                    duration: 400,
                    onFinish: () => {
                      console.info('animation end');
                    }
                  }, () => {
                    this.isContentShow = !this.isContentShow;
                    this.selectItem = item;
                  })
                })
              
              if (this.selectItem === item) {
                Text('这是内容区域')
                  .backgroundColor(Color.Gray)
                  .width('100%')
                  .height(100)
              }
            }
            .backgroundColor(0xFFFFFF)
            .width('100%')
            .margin({
              top: 10,
              bottom: 10
            })
          }
        }, (item: string) => item.toString())
      }
      .scrollBar(BarState.Off)
      .height('100%')
      .width('100%')
    }
    .backgroundColor(0xF1F3F5)
    .padding(12)
  }
}

在HarmonyOS Next中,手风琴动画可通过ArkUI的组件动画实现。使用ColumnList容器,结合transition属性定义展开/收缩的动画效果。通过animateTo函数控制状态切换,设置heightopacity等属性的过渡。示例代码片段:

// 控制展开状态
@State isExpanded: boolean = false;

// 点击触发动画
animateTo({ duration: 300 }, () => {
  this.isExpanded = !this.isExpanded;
})

在组件中绑定状态,动态调整高度即可实现手风琴效果。

在HarmonyOS Next中实现手风琴动画,可以通过ArkUI的组件动画能力结合布局变化来完成。核心是利用ColumnRow容器嵌套可折叠项,通过状态变量控制每一项的高度或宽度,并添加属性动画实现平滑过渡。

基本实现步骤:

  1. 定义数据结构与状态:使用@State装饰器定义控制每个手风琴项展开/折叠的状态数组(如isExpandedArray: boolean[])和当前活动项索引。

  2. 构建布局结构:使用Column(垂直手风琴)或Row(水平手风琴)作为容器。每个子项是一个自定义组件,通常包含:

    • 标题栏(FlexTextImage):点击时触发状态变更。
    • 内容区域(ColumnText等):其高度或宽度根据isExpanded状态动态绑定。
  3. 动态绑定内容区尺寸

    • 垂直方向:内容区的高度可绑定为isExpanded ? 固定值或自适应内容 : 0
    • 水平方向:内容区的宽度可绑定为isExpanded ? 固定值或比例 : 0
  4. 添加动画效果:在内容区域上使用.animation方法,为高度或宽度的变化添加动画。推荐使用animateTo显式动画或属性动画的隐式方式。

    • 示例(隐式动画)
      @Component
      struct AccordionItem {
        @State isExpanded: boolean = false;
        build() {
          Column() {
            // 1. 标题栏
            Flex({ justifyContent: FlexAlign.SpaceBetween }) {
              Text('标题')
              Image(this.isExpanded ? $r('app.media.arrow_up') : $r('app.media.arrow_down'))
            }
            .onClick(() => {
              this.isExpanded = !this.isExpanded; // 点击切换状态
            })
      
            // 2. 内容区域 - 高度动画
            Column() {
              Text('详细内容...')
            }
            .height(this.isExpanded ? 'auto' : 0) // 高度变化
            .clip(true) // 裁剪超出部分
            .animation({ duration: 300, curve: Curve.EaseInOut }) // 添加动画
          }
        }
      }
      
  5. 控制单项展开(可选):若需同时只展开一项,在标题栏点击事件中,先关闭所有项,再打开当前项,并更新状态数组。

关键点:

  • 动画曲线:使用Curve.EaseInOut等使过渡更自然。
  • 裁剪:为内容区域设置.clip(true),防止折叠时内容溢出。
  • 性能:对于复杂内容,可考虑使用TransitionLazyForEach优化渲染。

此方案利用ArkUI响应式UI与动画API,可高效实现平滑的手风琴交互效果。

回到顶部