ITPub博客

首页 > 应用开发 > IT综合 > HarmonyOS 属性动画开发示例(ArkTS)

HarmonyOS 属性动画开发示例(ArkTS)

IT综合 作者:HarmonyOS开发者社区 时间:2023-11-23 15:25:30 0 删除 编辑

介绍

利用ArkUI组件不仅可以实现属性变化引起的属性动画,也可以实现父组件状态变化引起子组件产生动画效果,这种动画为显式动画。效果如图所示:

相关概念

显式动画 :提供全局animateTo显式动画接口来指定由于闭包代码导致的状态变化插入过渡动效。

属性动画 :组件的某些通用属性变化时,可以通过属性动画实现渐变过渡效果,提升用户体验。支持的属性包括width、height、backgroundColor、opacity、scale、rotate、translate等。

Slider :滑动条组件,通常用于快速调节设置值,如音量调节、亮度调节等应用场景。

完整示例

源码下载

环境搭建

我们首先需要完成HarmonyOS开发环境搭建,可参照如图步骤进行。 

软件要求

DevEco Studio 版本:DevEco Studio 3.1 Release。

HarmonyOS SDK 版本:API version 9。

硬件要求

设备类型:华为手机或运行在DevEco Studio上的华为手机设备模拟器。

HarmonyOS系统:3.1.0 Developer Release。

环境搭建

1.  安装DevEco Studio,详情请参考 下载和安装软件 。

2.  设置DevEco Studio开发环境,DevEco Studio开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:

●   如果可以直接访问Internet,只需进行 下载HarmonyOS SDK 操作。

●   如果网络不能直接访问Internet,需要通过代理服务器才可以访问,请参考 配置开发环境 。

3.  开发者可以参考以下链接,完成设备调试的相关配置:

使用真机进行调试

使用模拟器进行调试

代码结构解读

本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在源码下载或gitee中提供。

├──entry /src/ main /ets                / /  代码区

│  ├──common

│  │  └──constants

│  │     └──Const . ets                 // 常量类

│  ├──entryability

│  │  └──EntryAbility . ts              // 程序入口类

│  ├──pages

│  │  └──Index . ets                    // 动效页面入口

│  ├──view

│  │  ├──AnimationWidgets . ets         // 动画组件

│  │  ├──CountController . ets          // 图标数量控制组件

│  │  └──IconAnimation . ets            // 图标属性动画组件

│  └──viewmodel

│     ├──IconItem . ets                 // 图标类

│     ├──Point . ets                    // 图标坐标类

│     └──IconsModel . ets               // 图标数据模型

└──entry /src/ main /resources          / /  资源文件

页面入口

页面入口由AnimationWidgets(动效组件)、CountController(动效图标数量控制组件)组成。

其中CountController通过Slider滑动控制quantity(动效图标数量);AnimationWidgets根据quantity展示相应数量的图标,点击组件按钮后通过在animateTo的event闭包函数中改变mainFlag状态,跟mainFlag相关的样式属性的变化都会产生动画效果。

// Index.ets

@Entry

@Component

struct Index  {

@State  quantity :  number  =  Common . IMAGES_MIN ;

@Provide  iconModel :  IconsModel  = new IconsModel ( this . quantity ,  Common . OFFSET_RADIUS );

build () {

Column () {

// 动画组件

AnimationWidgets ({

        quantity : $ quantity

})

// 图标数量控制组件

CountController ({

        quantity : $ quantity

})

}

...

}

}


CountController组件通过Slilder滑动控制动效图标的数量,最少3个图标,最多6个图标。



// CountController.ets

@Component

export struct CountController  {

@Link  quantity :  number ;

build () {

Column () {

Row () {

Text ($ r ( 'app.string.count' ))

. textStyle ()

Text ( this . quantity )

. textStyle ()

}

...

Slider ({

        value : this . quantity ,

        min :  Common . IMAGES_MIN ,

        max :  Common . IMAGES_TOTAL ,

        step : 1 ,

        style :  SliderStyle . InSet

})

. blockColor ( Color . White )

. selectedColor ($ r ( 'app.color.SliderSelectColor' ))

. showSteps ( true )

. trackThickness ($ r ( 'app.float.size_20' ))

. onChange (( value :  number ) => {

this . quantity  =  value ;

})

...

}

}

}


显式动画

点击AnimationWidgets组件的中心图标,调用animateTo方法,在event回调方法中改变状态,从而对组件本身产生缩放动画,和图标位置变化的动画效果,效果如图所示:

在animationTo的回调中修改mainFlag状态,所有跟mainFlag状态相关的属性变化都会产生过渡动画效果。



// AnimationWidgets.ets

export struct AnimationWidgets  {

@State  mainFlag : boolean = false ;

@Link @Watch ( 'onQuantityChange' )  quantity :  number ;

@Consume  iconModel :  IconsModel ;

onQuantityChange () { // 监听图标数量的变化,并修改图标数据以及对应的坐标位置

this . iconModel . addImage ( this . quantity );

}

aboutToAppear () {

this . onQuantityChange ();

}

animate () {

animateTo (

{

        delay :  Common . DELAY_10 ,

        tempo :  Common . TEMPO ,

        iterations : 1 ,

        duration :  Common . DURATION_500 ,

        curve :  Curve . Smooth ,

        playMode :  PlayMode . Normal

}, () => {

this . mainFlag  = ! this . mainFlag ;

})

}

build () {

Stack () {

Stack () {

ForEach ( this . iconModel . imagerArr , ( item :  IconItem ) => {

IconAnimation ({

            item :  item ,

            mainFlag : $ mainFlag

})

}, ( item :  IconItem ) =>  JSON . stringify ( item . index ))

}

. rotate ({

        x : 0 ,

        y : 0 ,

        z : 1 ,

        angle : this . mainFlag  ?  Common . ROTATE_ANGLE_360  : 0

})

...

Image (

this . mainFlag

? $ r ( "app.media.imgActive" )

: $ r ( "app.media.imgInit" )

)

. scale ({

          x : this . mainFlag  ?  Common . INIT_SCALE  : 1 ,

          y : this . mainFlag  ?  Common . INIT_SCALE  : 1

})

. onClick (() => {

this . iconModel . reset (); //  重置图标激活状态

this . animate (); // 启动显式动画

})

...

}

}

}


属性动画

组件的通用属性发生变化时,可以创建属性动画进行渐变,提升用户体验。示例效果如图所示:

当组件由animation动画属性修饰时,如果自身属性发生变化会产生过渡动画效果。本示例中当点击小图标时会触发自身clicked状态的变化,所有跟clicked相关的属性变化(如translate、rotate、scale、opacity)都会被增加动画效果。


// IconAnimation.ets

export struct IconAnimation  {

@Link  mainFlag : boolean ;

@ObjectLink  item :  IconItem ;

build () {

Image ( this . item . image )

. width ( Common . ICON_WIDTH )

. height ( Common . ICON_HEIGHT )

. objectFit ( ImageFit . Contain )

. translate (

this . mainFlag

? {  x : this . item . point . x ,  y : this . item . point . y  }

: {  x : 0 ,  y : 0 }

)

. rotate ({

        x : 0 ,

        y : 1 ,

        z : 0 ,

        angle : this . item . clicked  ?  Common . ROTATE_ANGLE_360  : 0

})

. scale (

this . item . clicked

? {  x :  Common . SCALE_RATIO ,  y :  Common . SCALE_RATIO  }

: {  x : 1 ,  y : 1 }

)

. opacity ( this . item . clicked  ?  Common . OPACITY_06  : 1 )

. onClick (() => {

this . item . clicked  = ! this . item . clicked ;

})

. animation (

{

          delay :  Common . DELAY_10 ,

          duration :  Common . DURATION_1000 ,

          iterations : 1 ,

          curve :  Curve . Smooth ,

          playMode :  PlayMode . Normal

}

)

}

}


根据图标数量计算图标位置。


// IconsModel.ets

import  Common from  '../common/constants/Const' ;

import  IconItem from  './IconItem' ;

import  Point from  './Point' ;

const  TWO_PI :  number  = 2 *  Math . PI ;

@Observed

export  class IconsModel {

public  imagerArr :  Array < IconItem > = [];

private  num :  number  =  Common . IMAGES_MIN ;

private  radius :  number ;

constructor ( num :  number ,  radius :  number ) {

this . radius  =  radius ;

this . addImage ( num );

}

public addImage ( num :  number ) {

this . num  =  num ;

if ( this . imagerArr . length  ===  num ) {

return ;

}

if ( this . imagerArr . length  >  num ) {

this . imagerArr . splice ( num , this . imagerArr . length  -  num );

} else {

for ( let i  = this . imagerArr . length ;  i  <  num ;  i ++ ) {

const  point  = this . genPointByIndex ( i );

this . imagerArr . push ( new IconItem ( i ,  Common . IMAGE_RESOURCE [ i ], false ,  point ));

}

}

this . refreshPoint ( num );

}

public refreshPoint ( num :  number ) {

for ( let i  = 0 ;  i  <  num ;  i ++ ) {

this . imagerArr [ i ]. point  = this . genPointByIndex ( i );

}

}

public genPointByIndex ( index :  number ):  Point  {

const  x  = this . radius  *  Math . cos ( TWO_PI  *  index  / this . num );

const  y  = this . radius  *  Math . sin ( TWO_PI  *  index  / this . num );

return new Point ( x ,  y );

}

public reset () {

for ( let i  = 0 ;  i  < this . num ;  i ++ ) {

if ( this . imagerArr [ i ]. clicked ) {

this . imagerArr [ i ]. clicked  = false ;

}

}

}

}


总结

您已经完成了本次Codelab的学习,并了解到以下知识点:

1.  如何使用animateTo实现显式动画。

2.  如何使用animation为组件添加属性动画。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70047792/viewspace-2996849/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2021-11-18

  • 博文量
    401
  • 访问量
    296735