HarmonyOS开发(八):动画及网络

news/2024/7/21 9:16:22 标签: harmonyos, 华为

1、动画概述

在ArkUI中,产生动画的方式是改变组件属性值并且指定相关的动画参数。当属性值发生变化后,按照动画参数,从原来的状态过渡到新的状态,就形成一个动画。

动画的相关参数如下:

属性名称

属性类型

默认值

描述

duration

number

1000

动画时长,单位为毫秒,默认时长为1000毫秒。

temponumber1.0动画播放的速度,值越大则播放越快,值越小则播放越慢,0则表示没有动画效果
curveCurveCurve.Linear

动画变化曲线,默认曲线为线性

其中可取值有如下一些

Liner:表示从头到尾的速度都是相同的

Ease:表示以低速开始,然后加快,在结束前变慢CubicBezier(0.25,0.1,0.25,1.0)

EaseIn:表示以低速开始 CubicBezier(0.42,0.0,1.0,1.0)

EaseOut:表示以低速结束 CubicBezier(0.0,0.0,0.58,1.0)

EaseInOut:表示以低速开始和结束 CubicBezier(0.42,0.0,0.58,1.0)

FastOutSlowIn:标准曲线 CubicBezier(0.4,0.0,0.2,1.0)

LinearOutSlowIn:减速曲线 CubicBezier(0.0,0.0,0.2,1.0)

FastOutSlowIn:加速曲线 CubicBezier(0.4,0.0,1.0,1.0)

ExtremeDeceleratioin:急缓曲线 CubicBezier(0.0,0.0,0.0,1.0)

sharp:锐利曲线 CubicBezier(0.33,0.0,0.67,1.0)

Rhythm:节奏曲线 CubicBezier(0.7,0.0,0.2,1.0)

Smooth:平滑曲线 CubicBezier(0.4,0.0,0.4,1.0)

Friction:阻尼曲线 CubicBezier(0.2,0.0,0.2,1.0)

delaynumber0延时播放时间,单位为毫秒,默认不延时播放
iterationsnumber1播放次数,默认为1次,设置为-1则表示无限次播放
playModePlayModePlayMode.Normal

设置动画播放模式,默认播放完后重头播放

Normal:正常播放

Reverse:动画反向播放

Alternate:动画在奇数次正向播放,偶数次反向播放

AlternateReverse:动画在奇数次反向播放,偶数次正向播放

onFinishfunction动画播放结束时回调函数

2、动画分类

  • 从页面分类分为:页面内的动画(在一个页面中即可发生的动画)、页面间的动画(两个页面跳转时会产生的动画)
  • 按基础能力可分为:属性动画、显示动画、转场动画

3、页面内动画

3.1、布局更新动画

显示动画(animateTo)和属性动画(animation)是ArkUI提供的最基础和常用的动画功能。

在布局属性(如:尺寸、位置等属性)发生变化时,可以通过属性动画或显示动画,按动画参数过渡到新的布局参数状态。

动画类型特点
显示动画(函数)闭包内的变化均会触发动画,包含币数据变化引起的组件增删
属性动画(属性方法)属性变化自动触发动画。(注意:属性值的变化需要加在animation属性之前)

3.1.1、使用显示动画产生布局更新动画

显示动画的接口:

animateTo(value:AnimateParam, event: () => void): void

第一个参数:指定动画参数

第二个参数:动画的闭包函数

3.1.2、相关实例

@Entry
@Component
struct LayoutChangeTest {
  @State itemAlign: HorizontalAlign = HorizontalAlign.Start;
  aligns: HorizontalAlign[] = [HorizontalAlign.Start, HorizontalAlign.Center, HorizontalAlign.End];
  alignIndex: number = 0;

  build() {
    Column({space: 30}) {
      Text('修改布局位置')
        .fontSize(30)
        .margin({top: 100})

      Column({space: 25}) {
        Text("JavaScript").fontSize(20).fontWeight(FontWeight.Bolder).fontColor('#4e72b8')
        Text("TypeScript").fontSize(20).fontWeight(FontWeight.Bolder).fontColor('#6d8346')
        Text("ArkTS").fontSize(20).fontWeight(FontWeight.Bolder).fontColor('#69541b')
      }
      .margin(20)
      .alignItems(this.itemAlign)
      .justifyContent(FlexAlign.Center)
      .borderWidth(2)
      .width('90%')
      .height(200)

      Button('Click', {type: ButtonType.Capsule, stateEffect: true})
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .width('50%')
        .onClick(() => {
          // 显示动画
          animateTo({duration: 1000, curve: Curve.EaseInOut},() => {
            // 在闭包函数中修改上方元素的对齐方式
            this.alignIndex = (this.alignIndex + 1) % this.aligns.length;
            this.itemAlign = this.aligns[this.alignIndex];
          })
        })
    }
    .width('100%')
    .height('100%')
  }
}
@Entry
@Component
struct LayoutChangeTest1 {
  @State mySize: number = 30;
  // 标志位,用来控制组件的大小
  @State flag: boolean = false;

  build() {
    Column( {space: 20} ) {
      Text('HarmonyOS')
        .fontColor('#ed1941')
        .fontWeight(FontWeight.Bolder)
        .fontSize(this.mySize)
        .margin(10)

      Button(this.flag ? '缩小': '放大', {type:ButtonType.Capsule,stateEffect:true})
        .width('50%')
        .fontSize(16)
        .onClick(() => {
          animateTo({duration: 1000, curve: Curve.Ease}, () => {
            if(this.flag) {
              this.mySize = 30;
            } else {
              this.mySize = 50;
            }
            this.flag = !this.flag;
          });
        })
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height('100%')
  }
}
@Entry
@Component
struct LayoutPage2 {
  @State message: string = '改变角度';
  @State rotateAngle: number = 0;
  @State flag: boolean = false;
  
  build() {
    Row() {
      Column({space:15}) {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
        Image($r('app.media.image2'))
          .width(200)
          .height(200)
          .borderRadius(100)
          .rotate({
            x: 1,
            y: 1,
            z: 1,
            angle: this.rotateAngle
          })
          .onClick(() => {
            animateTo({},() => {
              if(this.flag) {
                this.rotateAngle = 0;
              } else {
                this.rotateAngle = 640;
              }
              this.flag = !this.flag;
            })
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

3.1.3、使用属性动画产生布局更新动画

显示动画是把要执行动画的属性修改放在闭包函烽中触发动画,而属性动画则不需要使用闭包,只需要把animation属性加在要做属性动画的组件的属性后就可以了。

属性动画接口

animation(value: AnimateParam)

参数value表示动画参数。

注意:如果希望某个属性值的变化而产生动画,则需要此属性需要加到animation属性之前。

3.1.4、相关案例

@Entry
@Component
struct AttrAnimationTest1 {
  @State widthSize: number = 250;
  @State heightSize: number = 100;
  @State rotateAngle: number = 0;
  @State flag: boolean = true;

  build() {
    Row() {
      Column() {
        Button('change size')
          .onClick(() => {
            if(this.flag) {
              this.widthSize = 150;
              this.heightSize = 50;
            } else {
              this.widthSize = 250;
              this.heightSize = 100;
            }
            this.flag = !this.flag;
          })
          .margin(30)
          .width(this.widthSize)
          .animation({
            duration:2000,
            iterations:3,
            curve: Curve.Linear,
            playMode: PlayMode.Alternate
          })
          .height(this.heightSize)
          .animation({
            duration:1000,
            curve: Curve.Linear,
            playMode:PlayMode.Alternate
          })

        Button('change rotate angle')
          .onClick(() => {
            this.rotateAngle = 90;
          })
          .margin(50)
          .rotate({angle: this.rotateAngle})
          .animation({
            duration:1000,
            iterations:-1,
            curve:Curve.Linear,
            playMode:PlayMode.Alternate
          })

      }
      .width('100%')
    }
    .height('100%')
  }
}

4、组件内转场动画

组件内转场动画使用transition,它常见的用法如下:

1、if/else产生组件内转场动画

2、ForEach产生组件内转场动画

组件的插入、删除过程即为组件本身的转场过程,通过设置转场动画,可以定义组件出现、消失的效果。

组件内转场动画的接口:

transition(value: TransitionOptions)

transition函数的入参为组件内转场的效果,可以定义平移、透明度、旋转、缩放这几种转场样式的单个或者组件的转场效果,必须和animateTo一起使用才能产生组件转场效果。

transition常见用法

1、组件的插入、删除使用同一个动画效果

Button()
 .transition({type: TransitionType.All, scale: {x: 0, y: 0 }})

当type属性为TransitionType.All时,表示指定转场动效生效在组件的所有变化(插入和删除)场景,这个时候删除动画和插入动画是相反的过程。

 2、组件的插入、删除使用不同的动画效果

Button()
 .transition({type: TransitionType.Insert, translate: {x: 200, y: -200}, opacity: 0})
 .transition({type: TransitionType.Delete, rotate: {x: 0, y:0, z:1, angle:360}})

3、只定义组件的插入或删除其中一种动画效果

Button()
 .transition({type: TransitionType.Delete, translate:{x: 200,y: -200}})

4.1、if/else产生组件内转场动画

@Entry
@Component
struct TransitionTest {
  @State flag: boolean = true;

  build() {
    Row() {
      Column() {
        Button(this.flag ? '隐藏' : '显示')
          .fontSize(20)
          .margin(30)
          .width(150)
          .height(50)
          .onClick(() => {
            // 在animateTo闭包中改变flag的值
            animateTo({duration:1500},() => {
              // 点击按钮来控制标记变量
              this.flag = !this.flag;
            })
          })
        if(this.flag) {
          Text('HarmonyOS')
            .fontSize(20)
            .fontWeight(FontWeight.Bolder)
            .fontColor('#008792')
            // 添加转场效果
            .transition({type: TransitionType.Insert, translate: {x: 200, y: -200}})
            .transition({type: TransitionType.Delete, opacity: 0, scale: {x: 0, y: 0}})
        }

      }
      .width('100%')
    }
    .height('100%')
  }
}

4.2、ForEach产生组件内转场动画

ForEach可通过控制数组中的元素个数,来控制组件的插入和删除。通过ForEach来产生组件内转场动画,需要两个条件

1、ForEach里的组件配置了transition效果

2、在animateTo的闭包中控制组件的插入或删除,即控制数组的元素添加和删除

@Entry
@Component
struct ForEachTest {

  @State books :string[] = [
    '《JavaScript学习指南》',
    '《TypeScript从入门到精通》',
    '《ArkTS学习手册》',
    '《JAVA核心卷》'
  ];

  num: number = 0;

  build() {
    Column({space: 10}) {
      Column(){
        // 注意 这里遍历的key是使用item,所以我们在添加时加上一个num来区分内容
        ForEach(this.books, (item) => {
          Text(item).textStyle()
            .transition({type: TransitionType.All, translate: {x: 200},scale:{x:0,y:0}})
        },item => JSON.stringify(item))
      }.columnStyle()

      Button('头部添加元素').ButtonStyle('#375830', () => {
        animateTo({}, () => {
          this.num++;
          this.books.unshift(`《C语言编程思想》_${this.num}`)
        })
      })

      Button('头部删除元素').ButtonStyle('#b64533', () => {
        animateTo({}, () => {
          this.books.shift()
        })
      })

      Button('尾部删除元素').ButtonStyle('#dea32c', () => {
        animateTo({}, () => {
          this.books.pop()
        })
      })

    }
    .width('100%')
    .height('100%')
  }
}

// 相关样式信息
@Extend(Text) function textStyle() {
  .width(300)
  .height(60)
  .fontSize(18)
  .margin({top: 3})
  .backgroundColor('#d3c6a6')
  .textAlign(TextAlign.Start)
  .fontColor(Color.White)
}

@Extend(Column) function columnStyle() {
  .margin(10)
  .justifyContent(FlexAlign.Start)
  .alignItems(HorizontalAlign.Center)
  .width('90%')
  .height('50%')
}

@Extend(Button) function ButtonStyle(color: string|Color, click: Function) {
  .width(200)
  .height(50)
  .fontSize(18)
  .backgroundColor(color)
  .onClick(() => {
    // click代表的就是调用时具体传入进来的函数
    click()
  })
}

5、页面间的动画

5.1、共享元素转场动画

在不同的页面间,有使用相同元素的场景,可以使用共享元素转场动画衔接。

共享元素转场的接口:

sharedTransition(id: string, options?: sharedTransitionOptions)

其中id为指定共享元素的组件id

根据sharedTransitionOptions中的type参数,可以把共享元素转场分为Exchange类型和Static类型。

5.1.1、Exchange类型

交换型共享元素转场。

这种类共享元素转场适用于两个页面间相同元素的衔接,从起始页共享元素的位置、大小过渡到目标页面的共享元素的位置、大小。

当不指定type时,默认就是Exchange类型的共享转场

使用Exchange类型的共享转场时,共享元素转场的动画参数由目标页面options中的动画参数决定。

5.1.2、Static类型的共享元素转场

静态类型的共享元素转场常用于页面跳转时,标题的渐入淡出,只需要在一个页面中有Static的共享元素,不能在两个页面中出现相同id的Static类型的共享元素。

// Src.ets
import router from '@ohos.router';

@Entry
@Component
struct Src {

  build() {
    Column({ space: 30 }) {
      // Exchange类型共享转场
      Image($r('app.media.image2'))
        .width(50)
        .height(50)
        .opacity(.3)
        .borderRadius(75)
        .sharedTransition('img1',{
          duration: 1000,
          curve: Curve.Linear
        })
    }
    .onClick(() => {
      // 路由跳转
      router.pushUrl({url: "pages/SharedTransition/Dest"});
    })
    .padding(10)
    .width('100%')
    .height('100%')
    .alignItems(HorizontalAlign.Start)
  }
}
// Dest.ets
import router from '@ohos.router';

@Entry
@Component
struct Dest {

  build() {
    Column({ space: 30 }) {
      // 配置Static类型的共享元素转场
      Text('鸿蒙系统')
        .fontSize(20)
        .fontColor('#6d8346')
        .opacity(.8)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 10 })
        .sharedTransition('text',{
          duration: 500,
          curve: Curve.Linear,
          type: SharedTransitionEffectType.Static
        })
      // 配置Exchange类型的共享元素转场,id是'img1'
      Image($r('app.media.image2'))
        .width(150)
        .height(150).opacity(1)
        .borderRadius(75)
        .sharedTransition('img1',{
          duration: 500,
          curve: Curve.Linear
        })
    }
    .width('100%')
    .height('100%')
    .alignItems(HorizontalAlign.Center)
    .onClick(() => {
      // 返回
      router.back();
    })
  }
}

5.2、页面转场动画

两个页面之间发生跳转,一个页面消失,另一个页面出现,此时可以配置各自页面的页面转场参数实现自定义的页面转场效果。

页面转场效果写在pageTransition函数中,通过PageTransitionEnter和PageTransitionExit来指定页面进入和退出时的动画效果。

pageTransitionEnter接口

PageTransitionEnter({type?: RouteType, duration?: number, curve?: Curve | string, delay: number})

pageTransitionEnter提供了onEnter接口进行自定义页面入场动画的回调

pageTransitionExit接口

PageTransitionExit({type?: RouteType, duration?: number, curve?: Curve | string, delay: number})

pageTransitionExit提供了onExit接口进行自定义页面退场动画的回调

关于RouteType表示路由生效类型,从一个页面到另一个页面有两人种方式,一种是push,一种是back(pop出栈),那么type参数就可以由开发者指定哪种类型的路由来定义转场效果。对于push和back会有一些区别,比如A页面到B页面push时,A页面是退场,B页面是入场,如果B页面back回A页面则是B页面退场,A页面入场。

type参数的默认值是RouteType.None表示对页面的push和pop都生效

如果我们把页面转场时长设置为0(duration参数值为0)则无页面转场动画。

// Src2.est
import router from '@ohos.router';

@Entry
@Component
struct Src2 {
  @State scale1: number = 1;
  @State opacity1: number = 1;

  build() {
    Column({ space: 30}) {
      Text('Src2...')
        .fontSize(30)
        .opacity(this.opacity1)
        .margin({bottom: 15})
      Image($r('app.media.image2'))
        .width(300)
        .height(400)
        .scale({x: this.scale1})
        .opacity(this.opacity1)
    }
    .width('100%')
    .height('100%')
    .onClick(() => {
      router.pushUrl({
        url: "pages/pageTransition/Dest2"
      })
    })
  }

  pageTransition() {
    PageTransitionEnter({}).onEnter((type: RouteType, progress: number) => {
      this.scale1 = 1;
      this.opacity1 = progress;
    })

    PageTransitionExit({}).onExit((type: RouteType, progress: number) => {
      this.scale1 = 1 - progress;;
      this.opacity1 = 1 - progress;
    })
  }

}
// Dest2.est
import router from '@ohos.router';

@Entry
@Component
struct Dest2 {
  @State scale1: number = 1;
  @State opacity1: number = 1;

  build() {
    Column(){
      Text('Dest2...')
        .fontSize(30)
        .opacity(this.opacity1)
        .margin({bottom: 15})
      Image($r('app.media.image2'))
        .width(300)
        .height(400)
        .scale({y: this.scale1})
        .opacity(this.opacity1)
    }
    .width('100%')
    .height('100%')
   .onClick(() => {
     router.back()
   })
  }

  pageTransition() {
    PageTransitionEnter({}).onEnter((type: RouteType, progress: number) => {
      this.scale1 = progress;
      this.opacity1 = progress;
    })

    PageTransitionExit({}).onExit((type: RouteType, progress: number) => {
      this.scale1 = 1 - progress;
      this.opacity1 = 1 - progress;
    })

  }

}

6、网络

6.1、基于web组件构建网络应用

当需要访问网络资源的时候需要在module.json5中申请网络访问权限:ohos.permission.INTERNET

Web组件的使用只需要ArkTS文件中创建一个Web组件,传入两个参数就可以了。

src:指定了网页的路径

controller:组件控制器,绑定web组件,实现对web组件的控制

import webview from '@ohos.web.webview';

@Entry
@Component
struct WebComp {

  controller: WebviewController = new webview.WebviewController();

  build() {
    Row() {
      Column() {
        Web({
          src: 'https://www.baidu.com',
          controller: this.controller
        })
      }
      .width('100%')
    }
    .height('100%')
  }
}

6.2、HTTP数据请求

6.2.1、简单说明

开发的应用需要通过HTTP发送一个数据请求,支持的情求方式有:GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT

HTTP数据请求功能主要由http模块提供,这个功能也需要申请ohos.permission.INTERNET权限

相关的方法说明:

方法名称功能描述
createHttp()创建一个http请求
request()根据URL地址,发起HTTP网络请求
destroy()中断请求任务
on(type: 'headerReceive')订阅HTTP Response Header 事件
off(type: 'headerReceive')取消订阅HTTP Response Header事件

6.2.2、开发步骤

1、导入http模块

import http from '@ohos.net.http';

2、创建HTTP请求实例,生成HttpRequest对象

let httpRequest = http.createHttp();

注意:每一个httpRequest对应一个http请求任务,不可以复用

3、订阅HTTP响应头(可选)

4、根据URL地址,发起HTTP网络请求

5、处理HTTP响应头和HTTP网络请求的返回结果(可选)

// 导入模块
import http from '@ohos.net.http';

@Entry
@Component
struct HttpTest {
  url: string = 'https://mock.apifox.com/m1/3690335-0-default/getHot'
  @State titles: string[] = [];

  build() {
    Row() {
      Column() {
        Button('获取数据')
          .width('50%')
          .margin({bottom: 15})
          .onClick(() => {
            // 创建请求对象
            let httpReq = http.createHttp();
            // 发起请求
            httpReq.request(this.url,{
              method: http.RequestMethod.GET,
            }, (err,data) => {
              // 处理结果
              if(!err) {
                // this.titles = JSON.parse(`${data}`).values['title']
                let arr = JSON.parse(`${data.result}`).values
                for(let item of arr) {
                  this.titles.push(item['title']);
                }
              }
            })
          })
        ForEach(this.titles, (item) =>{
          Text(item)
            .fontSize(14)
            .margin({bottom:5})
        },item => item)
      }
      .width('100%')
    }
    .height('100%')
  }
}

6.2.3、http请求-Promise方式

使用这种方式是为了避免地狱回调的问题。

// 导入模块
import http from '@ohos.net.http';

@Entry
@Component
struct HttpPromiseTest {

  url: string = 'https://mock.apifox.com/m1/3690335-0-default/getHot'
  @State titles: string[] = [];

  build() {
    Row() {
      Column() {
        Button('获取数据')
          .width('50%')
          .margin({bottom: 15})
          .onClick(() => {
            // 创建http请求
            let httpReq = http.createHttp();
            // 发起请求
            let promise = httpReq.request(this.url)
            promise.then((data) => {
              let arr = JSON.parse(`${data.result}`).values
              for(let item of arr) {
                this.titles.push(item['title']);
              }
            })
          })

        ForEach(this.titles, (item) =>{
          Text(item)
            .fontSize(14)
            .margin({bottom:5})
        },item => item)
      }
      .width('100%')
    }
    .height('100%')
  }
}


http://www.niftyadmin.cn/n/5231893.html

相关文章

微信小程序 地图撒点

1. 微信小程序 地图撒点 1.1 说明 首先使用微信小程序自带标签,并且设置好宽高让地图显示,用longitude和latitude表示中心点。   (1)show-location 显示带有方向的当前定位点,本项目不需要不添加。   (2&#xff…

MYSQL8.0 修改字符集和排序规则-企业实战

#MYSQL8.0 修改字符集和排序规则 由于MYSQL8.X 的排序规则从默认5.7的utf8_general_ci 修改为:utf8mb4_0900_ai_ci, 所以不管是MYSQL5.7迁移还是其他的操作导致排序规则更改都需要更改, 要不然会导致表关联join出错. #查询非utf8mb4_0900_ai_ci排序规则…

Unity | 渡鸦避难所-0 | 创建 URP 项目并导入商店资源

0 前言 知识点零零碎碎,没有目标,所以,一起做游戏吧 各位老师如果有什么指点、批评、漫骂、想法、建议、疑惑等,欢迎留言,一起学习 1 创建 3D(URP)项目 在 Unity Hub 中点击新项目&#xff…

【Android 线程】在子线程中更新UI

线程 2 种基本用法 继承 //定义 class MyThread : Thread() {override fun run() {} } //启动 MyThread.start()接口 //定义 class MyThread : Runnable {override fun run() {} } //启动 var myThread MyThread() Thread(myThread).start()在子线程中更新UI class MainAc…

基于python的FMCW雷达工作原理仿真

这篇文章将介绍如何使用python来实现FMCW工作原理的仿真,第1章内容将介绍距离检测原理,第2章内容会介绍速度检测原理。 第1章 第1部分: 距离检测原理 调制的连续波雷达通常也被叫做调频连续波(FMCW)雷达是一个使用频率调制来测量…

MQTT分析——CONNECT为例子

源代码: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Net.Sockets;namespace ConsoleApp1 {class Program{static void Main(string[] args){Connect();}/// <summary>/// 向…

CSS新手入门笔记整理:CSS图片样式

图片大小 语法 width:像素值; height:像素值; 图片边框&#xff1a;border 语法 边框&#xff1a;宽度值 样式值 颜色值&#xff1b; border:1px solid red; 图片对齐 水平对齐&#xff1a;text-align 语法 text-align:取值; 属性值 说明 left 左对齐(默认值) cent…

Django回顾【四】之模型层

目录 一、基本使用 1、ORM框架 2、创建表 二、常用和非常用字段 三、常用和非常用字段参数 四、settings配置 五、基本操作 5.1 增加表记录 5.2 删除表纪录 5.3 更新表纪录 5.4 查询表纪录 六、 多表操作-创建关系 七、基于对象的跨表查询 八、基于链表的跨表…