HarmonyOS鸿蒙Next中如何自定义实现卡片展开/收起动态效果?

HarmonyOS鸿蒙Next中如何自定义实现卡片展开/收起动态效果? 如何自定义实现卡片展开/收起动态效果?

3 回复

实现效果

cke_262.png

实现思路

第一步:创建基础的布局页面。

第二步:添加状态变量以此来控制每一个卡片展开/收起状态,通过数组数量来进行处理。

第三步:添加基本动画效果,让展开/收起更加丝滑

应用场景

在一些新闻资讯流或者设置页面都比较常见。

完整代码

// 定义卡片数据接口
interface CardInfo {
  title: string
  content: string
}

@Entry
@Component
struct ToggleCard {
  // 使用数组管理多个卡片的展开状态
  @State cardsExpanded: boolean[] = [false, false, false]

  // 卡片数据
  @State cardsData: CardInfo[] = [
    {
      title: '你需要的不是山水',
      content: '对于山水的欣赏,是一种审美能力,更是一种心境。田间的农夫看到的是再普通不过的秧苗和土地,一个诗人看到的也许就是青翠原野、蓝天白云以及由此派生出来的诗情画意。',
    },
    {
      title: '你的坏情绪让我很受伤',
      content: '对你影响不好,我只想对你说我陪了你十三年,心里的伤口就没有愈合过,孩子大了,为了孩子做回父亲的形象吧。你不要让孩子将来输在你的身上',
    },
    {
      title: '遗失在风中的爱情',
      content: '我多想抛开一切尘念,目空一切地活着,可是总有一些人,在我的世界里不经意间淡入淡出,无法割舍;总有一些事,镌刻在我的心里若隐若现,无法断念',
    }
  ]

  toggleCard(index: number) {
    animateTo({
      duration: 400,
      curve: Curve.EaseOut,
      onFinish: () => {

      }
    }, () => {
      let newExpandedState = [...this.cardsExpanded]
      newExpandedState[index] = !newExpandedState[index]
      this.cardsExpanded = newExpandedState
    })
  }

  build() {
    Column({ space: 20 }) {
      Text('卡片')
        .fontSize(22)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 20 })

      Scroll() {
        Column({ space: 16 }) {
          ForEach(this.cardsData, (card: CardInfo, index: number) => {
            Column() {
              Row() {
                Text(card.title)
                  .fontSize(16)
                  .fontWeight(FontWeight.Medium)

                Blank()

                Button() {
                  Image($r('sys.media.ohos_ic_public_arrow_down'))
                    .width(24)
                    .height(24)
                    .fillColor('#3F72AF')
                    .rotate({ angle: this.cardsExpanded[index] ? 180 : 0 })
                    .animation({
                      duration: 300,
                      curve: Curve.FastOutSlowIn
                    })
                }
                .width(36)
                .height(36)
                .backgroundColor(Color.Transparent)
                .onClick(() => this.toggleCard(index))
              }
              .width('100%')
              .justifyContent(FlexAlign.SpaceBetween)
              .alignItems(VerticalAlign.Center)

              if (this.cardsExpanded[index]) {
                Column({ space: 8 }) {
                  Text(card.content)
                    .fontSize(14)
                    .layoutWeight(1)
                }
                .animation({
                  duration: 300,
                  curve: Curve.EaseOut
                })
                .height(100)
                .width('100%')
              }
            }
            .padding(16)
            .borderRadius(12)
            .backgroundColor(Color.White)
            .width('100%')
            .shadow({
              radius: 4,
              color: 'rgba(0, 0, 0, 0.1)',
              offsetX: 0,
              offsetY: 2
            })
          })


          Blank()
            .height(20)
        }
        .alignItems(HorizontalAlign.Center)
      }
      .align(Alignment.Top)
      .padding(20)
      .layoutWeight(1)


      Row({ space: 20 }) {
        Button('全部展开')
          .width('40%')
          .onClick(() => {
            animateTo({
              duration: 300
            }, () => {
              this.cardsExpanded = this.cardsData.map((_: CardInfo) => true)
            })
          })

        Button('全部收起')
          .width('40%')
          .onClick(() => {
            animateTo({
              duration: 300
            }, () => {
              this.cardsExpanded = this.cardsData.map((_: CardInfo) => false)
            })
          })
      }
      .margin({ bottom: 30 })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
    .alignItems(HorizontalAlign.Center)
    .expandSafeArea()
  }
}

更多关于HarmonyOS鸿蒙Next中如何自定义实现卡片展开/收起动态效果?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中,自定义卡片展开/收起效果主要通过ArkUI的显式动画(如animateTo)和状态管理实现。使用条件渲染控制布局变化,结合height、opacity等属性过渡。关键步骤包括:定义展开状态变量,在animateTo中修改该变量触发UI更新,并设置animation参数控制动效时长与曲线。可搭配Column容器与属性动画实现平滑的高度变换。

在HarmonyOS Next中,自定义卡片展开/收起动态效果的核心是使用ArkUI的显式动画(如animateTo)配合布局属性的变化(如height、clip、scale等)。以下是关键实现步骤:

  1. 状态与布局定义:使用@State装饰器控制卡片的展开状态(如isExpanded: boolean)。在布局中,通常需要动态改变组件的高度、缩放或裁剪区域。例如,将内容区域包裹在FlexStackColumn中,并绑定heightclip属性。

  2. 动画触发与属性绑定:通过点击事件切换isExpanded状态,并在animateTo中执行属性变化。例如:

    animateTo({
      duration: 300,
      curve: Curve.EaseInOut
    }, () => {
      this.isExpanded = !this.isExpanded; // 触发高度等属性变化
    })
    
  3. 动态样式计算:根据isExpanded状态,计算卡片内容的高度或缩放比例。例如:

    // 使用条件表达式或方法返回样式值
    .height(this.isExpanded ? '100%' : '80vp')
    .clip({ 
      x: 0, 
      y: 0, 
      width: '100%', 
      height: this.isExpanded ? 'auto' : '120vp' 
    })
    
  4. 优化性能与交互:对于复杂动画,建议使用transition属性或PropertyAnimation精细化控制属性变化。避免在动画中频繁计算布局,可提前测量内容高度。

注意:HarmonyOS Next的ArkUI强调声明式UI,动画应优先通过状态驱动样式变更实现,而非直接操作组件。

回到顶部