OpenHarmony实战开发-如何通过属性动画实现UI中图标按下时,图标出现弹性缩放效果。

567 篇文章 1 订阅
555 篇文章 0 订阅

场景介绍

在日常开发过程中,通常会出现因为状态变化导致组件属性值发生变化,如:

  • 数字键盘按键时,对应数字按钮背景色加深,呈现被点击效果;放开按键时,呈现取消选中效果,
  • UI中图标按下时,图标出现弹性缩放效果,
  • 在做数据统计时,随着数据值的变化,统计曲线随之变化等动画效果, 本例将为大家介绍下如何通过属性动画实现上述场景。

效果呈现

效果图如下:

场景 效果图

场景1:属性动画 属性动画
在这里插入图片描述

场景2:弹性动态 弹性动态

在这里插入图片描述

场景3:曲线动画 时间曲线

在这里插入图片描述

运行环境

本例基于以下环境开发,开发者也可以基于其他适配的版本进行开发

  • IDE: DevEco Studio 3.1 Release
  • SDK: Ohos_sdk_public 3.2.12.5(APIVersion 9 Release)

场景1:属性动画

实现思路

本实例涉及到的主要特性及其实现方案如下:

  • 通过Column、Grid、button、Text等关键组件以及visibility属性搭建UI局框架,以及渲染数字按钮。
  • 设置状态变量flag,用来控制属性状态的变化,同时向Button组件添加onTouch事件,更新按钮的当前状态,从而可以根据监听到的按钮状态加载对应的动画效果。
  • 默认状态为按钮放开状态(flag为false)。
  • 当按钮按下时,更新按钮的状态(flag:false -> true)。
  • 当按钮放开时,更新按钮的状态(flag:true -> false)。
  • 根据按钮组件的按下/放开状态,通过三元运算判断,使用属性动画更新按钮的选中/取消效果。
  • 当按钮按下时,加载属性动画:按钮被选中效果。
  • 当按钮放开时,加载属性动画:按钮取消选中效果。

开发步骤

针对实现思路中所提到的内容,具体关键开发步骤如下:

1.通过Column、Grid、button、Text等关键组件以及visibility属性搭建UI框架,以及渲染数字按钮。 具体代码如下:

  private numGrid: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, -1, 0, -1]

  build() {
    Row() {
      Column() {
        Grid() {
          //通过ForEach循环遍历,显示数字数字按钮
          ForEach(this.numGrid, (item, index) => {
            GridItem() {
              Button() {
                Text(`${item}`)
                  .fontSize(30)
              }
              .backgroundColor('#fff')
              .width(100)
              .height(100)
              // item为-1时,数字按钮不显示
              .visibility(item == -1 ? Visibility.Hidden : Visibility.Visible)
            }
          }, item => item)
        }
        .columnsTemplate('1fr 1fr 1fr')
        .rowsTemplate('1fr 1fr 1fr 1fr')
        .columnsGap(10)
        .rowsGap(10)
        .width(330)
        .height(440)
      }
      .width('100%')
      .height('100%')
    }
  }

2.设置状态变量flag,用来控制属性状态的变化,同时向Button组件添加onTouch事件,更新按钮的当前状态,从而可以根据监听到的按钮状态加载对应的动画效果。

具体代码如下:

//状态变量flag,用于监听按钮按下和放开的状态,默认至为false(放开状态)
@State flag: boolean = false;
...
.onTouch((event:TouchEvent) => {
    //当按钮按下时,更新按钮的状态(flag:false -> true)
    if (event.type == TouchType.Down) {
        this.flag = true
        this.currIndex = index
    }
    //当按钮放开时,更新按钮的状态(flag:true -> false)
    if (event.type == TouchType.Up) {
        this.flag = false
    }
})

3.根据按钮组件的按下/放开状态,通过三元运算判断并更新按钮背景色。

具体代码如下:

Button(){
    ...
    // 当按钮被按下(flag变更为true)时,当前按钮backgroundColor属性变更("#fff" -> "#D2C3D5" )
    // 当按钮被放开(flag变更为false)时,当前按钮backgroundColor属性变更("#D2C3D5" -> "#FFF" )
    .backgroundColor(this.flag && this.currIndex == index ? '#D2C3D5' : '#fff')
    .animation({
        duration: 200
    })
}

完整代码

@Entry
@Component
struct Index {
  private currIndex: number = -1
  private numGrid: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, -1, 0, -1]
  //状态变量flag,用于监听按钮按下和放开的状态,默认至为false(放开状态)
  @State flag: boolean = false;

  build() {
    Row() {
      Column() {
        Grid() {
          ForEach(this.numGrid, (item, index) => {
            GridItem() {
              Button() {
                Text(`${item}`)
                  .fontSize(30)
              }
               // 当按钮被按下(flag变更为true)时,当前按钮backgroundColor属性变更("#fff" -> "#D2C3D5" )
			   // 当按钮被放开(flag变更为false)时,当前按钮backgroundColor属性变更("#D2C3D5" -> "#FFF" )
              .backgroundColor(this.flag && this.currIndex == index ? '#D2C3D5' : '#fff')
              .animation({
                duration: 200
              })
              .width(100)
              .height(100)
              .visibility(item == -1 ? Visibility.Hidden : Visibility.Visible)
              .onTouch((event:TouchEvent) => {
                //当按钮按下时,更新按钮的状态(flag:false -> true)
                if (event.type == TouchType.Down) {
                  this.flag = true
                  this.currIndex = index
                }
                //当按钮放开时,更新按钮的状态(flag:true -> false)
                if (event.type == TouchType.Up) {
                  this.flag = false
                }
              })
            }
          }, item => item)
        }
        .columnsTemplate('1fr 1fr 1fr')
        .rowsTemplate('1fr 1fr 1fr 1fr')
        .columnsGap(10)
        .rowsGap(10)
        .width(330)
        .height(440)
      }
      .width('100%')
      .height('100%')
    }
  }
}

场景2:弹性动效

实现思路

针对弹性动效,涉及到的主要特征分为两部分:

  • 组件描绘:先通过List、ListItem、Image等组件将控件表描绘出来。
  • 组件状态变化:设置状态变量downFlag,控制按钮的当前状态;同时向Column组件添加onTouch事件,监听组件的当前状态。
  • 组件默认状态为放开状态(downFlag:false)。
  • 当按下Image组件时,更新组件的状态为true。
  • 当放开Image组件时,更新组件的状态为false。
  • 动画播放:使用属性动画绘制Image组件不同状态下的曲线动画。
  • 组件按下,触发第一阶段缩小动效,370ms内将组件横纵尺寸均缩小到原尺寸的80%。
  • 组件放开,触发第二阶段放大动效,在370ms内将控件从当前尺寸恢复到原尺寸。

开发步骤

针对实现思路中所提到的内容,具体关键开发步骤如下:

1.通过List、ListItem、Image等组件将控件表描绘出来。

具体代码如下:

private arr: number[]=[1,2,3,4,5]

...
List({space:10}){
      ForEach(this.arr,(item,index)=>{
        ListItem(){
            Image($r("app.media.app_icon"))
              .width(80)
              .height(80)
        }
      })
    }
    .margin({top:20})
    .padding({left:20})
    .listDirection(Axis.Horizontal)

2.设置状态变量downFlag,控制Image组件的当前状态,同时向Image组件添加onTouch事件,获取并更新组件的当前状态,从而可以根据监听到的组件状态加载对应的动画效果。 具体代码如下:

...
// 状态变量downFlag,用于监听Image组件按下和放开的状态
@State downFlag: boolean = false;
...
// 添加onTouch事件,监听状态
.onTouch((event: TouchEvent) => {
    // 当Column组件按下时,组件的状态更新为true
    if (event.type == TouchType.Down) {
      this.downFlag = true 
    // 当Column组件按下时,组件的状态更新为false
    } else if (event.type == TouchType.Up) {
      this.downFlag = false
    }
  })

3.根据Image组件的按下/放开状态,呈现不同的弹性效果(按下时组件缩小,动画以阻尼曲线的形式缩小至0.8倍,放开时组件动画以阻尼曲线的形式恢复至初始大小)。 具体代码如下:

···
Image($r("app.media.app_icon"))
 // 当downFlag状态为按下(true)时,组件在370ms内缩小至0.5倍;当downFlag状态为放开(false)时,组件在370ms内恢复至初始大小;
.scale(this.downFlag ? { x: 0.8, y: 0.8 } : { x: 1, y: 1 })
.animation({
   duration: 370,
   curve: Curve.Friction
})

完整代码

@Entry
@Component
struct Index {
  // 状态变量downFlag,用于监听Image组件按下和放开的状态
  @State downFlag: boolean = false;
  private arr: number[]=[1,2,3,4,5]
  private curIndex : number = -1

  build() {
    List({space:10}){
      ForEach(this.arr,(item,index)=>{
        ListItem(){
            Image($r("app.media.app_icon"))
              // 当downFlag状态为按下(true)时,组件在370ms内缩小至0.8倍;当downFlag状态为放开(false)时,组件在370ms内恢复至初始大小;
              .scale(this.downFlag && this.curIndex == index ? { x: 0.8, y: 0.8 } : { x: 1, y: 1 })
              .animation({
                duration: 370,
                curve: Curve.Friction
              })
              .width(80)
              .height(80)
                // 添加onTouch事件,监听状态
              .onTouch((event: TouchEvent) => {
                // 当Image组件按下时,组件的状态更新为true
                if (event.type == TouchType.Down) {
                  this.downFlag = true
                  this.curIndex = index
                  // 当Image组件按下时,组件的状态更新为false
                } else if (event.type == TouchType.Up) {
                  this.downFlag = false
                }
              })
        }
      })
    }
    .margin({top:20})
    .padding({left:20})
     // 列表排列方向水平
    .listDirection(Axis.Horizontal)
  }
}

场景3:曲线动画

曲线动画可以使用不同的曲线属性,呈现出不同的动画。 ArkUI中,曲线动画有两种使用方式,一种是直接使用Curve类型的枚举,一种是导入ohos.curve模块并使用模块内定义的接口/属性。

实现思路

  • 设置自定义变量item,用于存放不同类型的曲线,本案例中主要有以下类型曲线:

1.Curve类型的枚举:

  • Linear:表示动画从头到尾的速度都是相同的。
  • EaseInOut:表示动画以低速开始和结束,CubicBezier(0.42,
    0.0, 0.58, 1.0)。
    Smooth:平滑曲线,cubic-bezier(0.4, 0.0, 0.4, 1.0)。

2.ohos.curve导入:

  • springCurve类的弹簧曲线。 通过Flex、Column、button组件将UI布局以及框架搭建。
  • Column组件内部通过ForEach,遍历展示每条曲线。
  • 设置状态变量flag,监听当前button的状态,同时向button组件添加onClick事件,更新按钮的状态,从而可以根据监听到的按钮状态加载对应的动画效果。
  • 向Text组件添加width属性,根据按钮的状态,在同一周期内,通过width的变化呈现曲线的不同动画。

开发步骤

设置自定义变量item,用于存放不同类型的曲线。

具体代码如下:

private items: object[] = [
    {
      color: '#a320bf',
      title: '线性曲线',
      // curve类型曲线:表示动画从头到尾的速度都是相同的。
      curve: Curve.Linear,
    },
    {
      color: '#17d4be',
      title: '低速结束曲线',
      // curve类型曲线:表示动画以低速结束
      curve: Curve.EaseInOut,
    },
    {
      color: '#0e2d8c',
      title: '平滑曲线',
      // curve类型曲线:平滑曲线
      curve: Curve.Smooth,
    },
    {
      color: '#d4bb19',
      title: 'Curves.spring',
      // ohos.curve导入的弹簧曲线,以初速度为20的弹簧进行平移
      curve: Curves.springCurve(20, 1, 1, 1.2),
    },

2.通过Flex、Column、button组件将UI布局以及框架搭建。

具体代码如下:

 Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) { 
     Column({ space: 50 }) {
        ...
     }
     .alignItems(HorizontalAlign.Start)
     .width('100%')
     .padding({ left: 12, right: 12, top: 22, bottom: 22 })
     
     Button(){
        Text("Go!")
        .fontSize(20)
        .fontColor('#fff')
    }
    .borderRadius(20)
    .fontColor('#FFFFFF')
    .fontSize('12fp')
    .fontWeight(FontWeight.Bolder)
    .backgroundColor('#15587c')
    .padding(25)
    .margin({top:50}) 
  }
  .height('100%')
  .backgroundColor('#F1F3F5')
  .padding({ left: '3%', right: '3%' })

3.Column组件内部通过ForEach,遍历展示每条曲线。

具体代码如下:

ForEach(this.items, (item, index) => {
  Text(item['title'])
    .fontSize(20)
    .fontColor('#FFFFFF')
    .height(80)
    .textAlign(TextAlign.Start)
    .backgroundColor(item['color'])
    .borderRadius(20)
    .padding({left:10})
}, item => JSON.stringify(item))

4.设置状态变量flag,监听当前button的状态,同时向button组件添加onClick事件,更新按钮的状态,从而可以根据监听到的按钮状态加载对应的动画效果。

具体代码如下:

//状态变量flag,用于监听按钮按下状态
@State flag: boolean = true
...
Button(){
}
// 通过点击事件,反转flag的值
.onClick(() => {
      this.flag = !this.flag
    }) 

5.向Text组件添加width属性,根据按钮的状态,在同一周期内,呈现不同效果的曲线动画。

具体代码如下:

ForEach(this.items, (item, index) => {
  Text(item['title'])
     ...
    // 当flag为true时,width为15%;当flag为false时,width为95%
    .width(this.flag ? '15%': '95%')
    .animation({ duration: 2000, curve: item['curve'] })
}, item => JSON.stringify(item)) 

完整代码

import Curves from '@ohos.curves';

@Entry
@Component
struct Index {
  // 状态变量flag,用于监听按钮按下状态
  @State flag: boolean = true
  private items: object[] = [
    {
      color: '#a320bf',
      title: '线性曲线',
      // curve类型曲线:表示动画从头到尾的速度都是相同的。
      curve: Curve.Linear,
    },
    {
      color: '#17d4be',
      title: '低速结束曲线',
      // curve类型曲线:表示动画以低速结束
      curve: Curve.EaseInOut,
    },
    {
      color: '#0e2d8c',
      title: '平滑曲线',
      // curve类型曲线:平滑曲线
      curve: Curve.Smooth,
    },
    {
      color: '#d4bb19',
      title: '弹簧曲线',
      // ohos.curve导入的弹簧曲线动画,以初速度为20的弹簧进行平移
      curve: Curves.springCurve(20, 1, 1, 1.2),
    },
  ]

  build() {
    Flex({
      direction: FlexDirection.Column,
      justifyContent: FlexAlign.Start,
      alignItems: ItemAlign.Center
    }) {
      Column({ space: 50 }) {
        ForEach(this.items, (item, index) => {
          Text(item['title'])
            .fontSize(20)
            .fontColor('#FFFFFF')
            // 当flag为true时,width为15%;当flag为false时,width为95%;
            .width(this.flag ? '15%': '95%')
            .height(80)
            .textAlign(TextAlign.Start)
            .backgroundColor(item['color'])
            // 2s之内完成动画展示,每条动画曲线按照item['curve']去展示
            .animation({ duration: 2000, curve: item['curve'] })
            .borderRadius(20)
            .padding({left:10})
        }, item => JSON.stringify(item))
      }
      .alignItems(HorizontalAlign.Start)
      .width('100%')
      .padding({ left: 12, right: 12, top: 22, bottom: 22 })

      Button(){
        Text("Go!")
          .fontSize(20)
          .fontColor('#fff')
      }
      .borderRadius(20)
      .fontColor('#FFFFFF')
      .fontSize('12fp')
      .fontWeight(FontWeight.Bolder)
      .backgroundColor('#15587c')
      .padding(25)
      .margin({top:50})
      // 通过点击事件,反转flag的值
      .onClick(() => {
        this.flag = !this.flag
      })
    }
    .height('100%')
    .backgroundColor('#F1F3F5')
    .padding({ left: '3%', right: '3%' })
  }
}

我这边特意整理了《鸿蒙语法ArkTS、TypeScript、ArkUI、实战开发视频教程》以及《鸿蒙生态应用开发白皮书V2.0PDF》《鸿蒙开发学习手册》(共计890页)鸿蒙开发资料等…希望对大家有所帮助:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

鸿蒙语法ArkTS、TypeScript、ArkUI等…视频教程:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

在这里插入图片描述

OpenHarmony APP开发教程步骤:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

在这里插入图片描述

鸿蒙生态应用开发白皮书V2.0PDF:https://docs.qq.com/doc/DZVVkRGRUd3pHSnFG

在这里插入图片描述

应用开发中级就业技术:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

在这里插入图片描述

应用开发中高级就业技术:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

在这里插入图片描述

南北双向高工技能基础:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

在这里插入图片描述

全网首发-工业级 南向设备开发就业技术:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

在这里插入图片描述

《鸿蒙开发学习手册》:

如何快速入门:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

1.基本概念
2.构建第一个ArkTS应用
3.……

在这里插入图片描述

开发基础知识:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS语言
9.……

在这里插入图片描述

基于ArkTS 开发:https://docs.qq.com/doc/DZVVBYlhuRkZQZlB3

1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……

在这里插入图片描述

  • 27
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值