【动图+代码】如何实现丝滑入场动效|鸿蒙动效开发笔记 02 原创

awa_Liny
发布于 2024-10-14 07:51
浏览
0收藏

这篇笔记将介绍一种 HarmonyOS NEXT 开发里,让组件丝滑入场的动效实现方式!

ヽ( ̄ω ̄( ̄ω ̄〃)ゝ 前置知识:

​GIF 案例,从 .animation() 到 Curves.springMotion|鸿蒙动效笔记 01​

和一点点鸿蒙开发基础(工程结构、ArkTS 语法)。


参考代码:

整个项目已经开源:

​Linys_Ani_Examples_NEXT on Github​

​Linys_Ani_Examples_NEXT on Github​


// defaults/defaults.ets
// 使用这个文件存储诸多默认值,以供统一调用

export function fontSize_Extra_Large() {
  return 36;
}

export function fontSize_Large() {
  return 24;
}

export function fontSize_Normal() {
  return 16;
}

export function fontSize_Icon_Button() {
  return 25;
}

export function click_effect_default() {
  let ce: ClickEffect = { level: ClickEffectLevel.LIGHT };
  return

// pages/FadeInExamples.ets
// 展示的页面

import Curves from '@ohos.curves';
import { click_effect_default, fontSize_Extra_Large, fontSize_Large } from '../defaults/defaults';

@Entry
@Component
struct FadeInExample {
  @State response: number = 0.55;
  @State dampingFraction: number = 0.825;
  @State labels: string[] = ["Meow", "¯\\_(ツ)_/¯", "( •̀ ω •́ )✧", "在一起", "(~o ̄3 ̄)~", "就可以!"]

  build() {

    Column({ space: 10 }) {
      Row({ space: 15 }) {
        Navigator({ target: 'pages/Index', type: NavigationType.Back }) {
          Text('󰃚')
            .fontWeight(FontWeight.Bold)
            .fontSize(fontSize_Extra_Large())
            .clickEffect(click_effect_default())
        }

        Text('浮现入场')
          .fontWeight(FontWeight.Bold)
          .fontSize(fontSize_Large())
      }
      .alignItems(VerticalAlign.Center)

      Scroll() {
        Column({ space: 10 }) {
          ForEach(this.labels, (text: string, index: number) => {
            item({ text: text, timeout: index })
          })
        }
      }.edgeEffect(EdgeEffect.Spring)

    }
    .justifyContent(FlexAlign.Start)
    .alignItems(HorizontalAlign.Start)
    .padding({ left: 20, right: 20, top: 10 })
  }
}

@Component
struct item {
  @State text: string = "";
  @State offset_y: number = 100;
  @State opa: number = 0;
  @State timeout: number = 0;

  build() {
    Column() {
      Text(this.text)
        .fontColor($r('app.color.start_window_background'))
        .fontWeight(FontWeight.Bold)
        .fontSize(fontSize_Large())

      Text(this.timeout.toString())
        .fontWeight(FontWeight.Bold)
        .fontSize(fontSize_Extra_Large())
        .fontColor($r('app.color.start_window_background'))
        .opacity(0.4)
        .textAlign(TextAlign.End)
        .width("100%")
    }
    // Basics
    .alignItems(HorizontalAlign.Start)
    .justifyContent(FlexAlign.Start)
    .backgroundColor($r('app.color.color_accent'))
    .width("100%")
    .borderRadius(22)
    .padding(16)
    // Entry animation
    .offset({ y: this.offset_y })
    .opacity(this.opa)
    .animation({ curve: Curves.springMotion(0.5, 0.7) })
    .onAppear(() => {
      setTimeout(() => {
        this.opa = 1;
        this.offset_y = 0;
      }, (this.timeout) * 100)
    })
  }
}

实现效果:

【动图+代码】如何实现丝滑入场动效|鸿蒙动效开发笔记 02-鸿蒙开发者社区

整体思路:

为了实现浮现的效果,我们从两个方面入手:【浮】和【现】。

【浮】

即上升效果,在这里我们用组件的​​ .offset​​() 属性实现。

.offset({ y: this.offset_y

于是通过更改 offset_y,我们可以让组件“灵魂出窍”——组件在布局上占有位置不变,只是显示上产生偏移,这个特性能避免一些布局错乱的问题。

(注意!在设置了 .offset() 的时候,组件检测点击(onClick)的位置也是不变的,并不会随着显示偏移而判定偏移!)

【现】

即出现(淡入)效果,我们可以通过组件的 ​​.opacity​​() 属性实现。

.opacity(this.opa)

这里的 opacity 指的是不透明度,1 为完全显示。0 为完全消失(但是占的空间还是占住的)。

只要我们让组件一开始 .opacity(0),一段时间后再 .opacity(1) 就能实现延迟显示的效果。这可以通过改变 opa 实现。

延迟变化

在每个组件被渲染出来的时候,它们都会执行一遍 .onAppear(()=>{}) 属性中所写的代码。

那么我们只需要在这个属性的回调中写一个延迟执行的函数,让它在被渲染出来(但是不透明度为0,并设置了位置偏移 )的时候就开始等,等一段时间后再真正地显示(不透明度设置为 1,位置偏移设置为 0)就能实现。

可以使用 .setTimeout(()=>{}, ms) 设置倒计时:

onAppear(() => {
      setTimeout(() => {
        this.opa = 1;
        this.offset_y = 0;
      }, (this.timeout) * 100)
    })

(并且对于列表中的每一项,这个等待的时间应该要一个比一个长,来实现“依次浮现”的效果。只要在 ForEach(如果你用了 ForEach 的话)里将组件本身就依次变化的索引 index 赋值给 this.timeout 就可以了。)

ForEach(this.labels, (text: string, index: number) => {
    item({ text: text, timeout: index })
})

过渡动画

然后便是过渡动画了。这个部分相对简单,只需要写一行 ​​.animation​​() 就可以。

如果搭配上​​上一篇笔记​​所记述的 springMotion,我们就可以实现一个 Q 弹的动画效果。

.animation({ curve: Curves.springMotion(0.5, 0.7) })

更多后话

这个效果的实现还是相对比较简单,且基础的。

不过文中所写的这个版本尚有诸多不足,如:当列表超级超级长的时候,一个个弹出的动画就太长了,没准我都划到底了,还在等上面的组件一个个浮现出来。

解决起来倒也简单——只需要另外写一个判断,一开始渲染的时候,只对在屏幕内的列表项目进行延迟时间的累计,在看不到的地方就统一延迟相同的数值(反正也看不见),这样整个动画的时长不会超过屏幕内项目数*延迟间隔。这个的代码实现就交给诸位读者啦~

同理,这个效果的属性也不局限于位置偏移和不透明度,模糊、颜色等都可以按照这个思路进行渐变/渐显,加入这个入场动画。

最后的最后,感谢你读到这里!咱们下一篇鸿蒙动效开发笔记再见!!(~o ̄3 ̄)~



©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
1
收藏
回复
举报
回复
    相关推荐