3.3 Image组件和ImageAnimator组件 原创 精华

不做加班狗
发布于 2022-5-31 20:30
浏览
2收藏

本节首先解决@Extend装饰器无法多页面复用的问题,介绍通过自定义组件实现标题和正文的样式复用。然后介绍图片展示组件Image和帧动画组件ImageAnimator,并同时讲解如何对图片应用图像效果及实现共享元素转场。

3.3.1 建立多页面可复用的组件

在《3.1.1 Text组件》这节中,我们使用了@Extend装饰器定义了title和body,实现快速定义并复用组件的自定义样式。但是,@Extend装饰器只能应用在定义该装饰器的页面里,无法通过export共享给其它页面调用。同时,如果在其它页面定义了同名的装饰器,如,另一个页面也定义了一个名为"title"或"body"的装饰器,会编译异常,提示重复的定义。

本小节建立两个自定义组件,解决@Extend装饰器的上述不足,实现多页面复用。其中:

@Component装饰的struct表示该结构体具有组件化能力,能够成为一个独立的组件,这种类型的组件也称为自定义组件。

本小节不打算展开对@Component装饰器的讲解,更多的声明式语法将在《第8章 基于TS扩展的声明式开发规范》中讲解。

在index.ets页面底部加入如下代码:

/**
 * H8标题
 */
@Component
export struct H8 {
  private text: string = ''
  private color: any = $r('app.color.fgLevel1')

  build() {
    Text(this.text)
      .fontSize($r('app.float.fontSizeH8'))
      .fontWeight(Number($r('app.float.fontWeightH8')))
      .fontColor(this.color)
      .fontFamily('sans-serif-condensed, sans-serif')
  }
}

/**
 * 正文文本
 */
@Component
export struct TextBody1 {
  private text: string = ''
  private color: any = $r('app.color.fgLevel1')

  build() {
    Text(this.text)
      .fontSize($r('app.float.fontSizeBody1'))
      .fontWeight(Number($r('app.float.fontWeightBody1')))
      .fontColor(this.color)
      .fontFamily('sans-serif-condensed, sans-serif')
  }
}

在下一小节演示如何引用并使用标题组件和正文组件。

3.3.2 Image组件

图片组件Image,用来渲染展示图片。

首先,建立ImageSample.ets页面,用于展示本小节的效果,初始化代码如下:

// 引用自定义组件
import {H8,TextBody1} from './index'

/**
 * 3.3.1 Image组件
 */
@Entry
@Component
struct ImageSample {
  build() {
    Stack({ alignContent: Alignment.TopStart }){
      Scroll() {
        Column({space:8}){
          // 返回首页
          Row({space:8}){
            Image($r("app.media.ic_back")).width(24).height(24)

            Navigator({ target: 'pages/index', type: NavigationType.Back }) {
              H8({text:'返回'}) // 调用自定义组件
            }
          }

          // TODO

        }.padding({left: $r('app.float.spaceLeft'), right: $r('app.float.spaceRight')}).alignItems(HorizontalAlign.Start)
      }
    }.width('100%').height('100%').backgroundColor($r("app.color.appBg")).padding({top:$r('app.float.spaceTop'), bottom:$r('app.float.spaceBottom')})
  }
}
1.接口:Image(src: string | PixelMap)

src:string|PixelMap 图片的URI,支持本地图片和网络路径,支持使用媒体PixelMap对象。

PixelMap:图像像素类,用于读取或写入图像数据以及获取图像信息。在调用PixelMap的方法前,需要先通过createPixelMap创建一个PixelMap实例。关于创建PixelMap实例的方法并不适合初学者学习,这里暂时不展开讨论,后面会有专门的章节详细讲解。本专栏教程是由浅入深、循序渐进、水到渠成的。

这里先演示如何通过接口引用App本地图片。图片格式支持“png/jpg/gif/svg”,图片文件可以存放在media媒体目录、rawfile目录或自己创建的“/common/images”目录。图片格式和图片存放目录没有对应关系,下面演示做了个随机分配,便于用最少代码做更全面的演示。

在上述初始化代码的”TODO“处加入如下代码:

          /**
           * 接口:Image(src: string | PixelMap)
           *    src:string|PixelMap 图片的URI,支持本地图片和网络路径,支持使用媒体PixelMap对象。
           *        PixelMap:图像像素类,用于读取或写入图像数据以及获取图像信息。在调用PixelMap的方法前,需要先通过createPixelMap创建一个PixelMap实例。
           */
          H8({text:'1.接口'})
          TextBody1({text:'png格式图片,media目录'})
          Image($r("app.media.cover")) // media目录下的媒体资源
            .width("100%")
            .aspectRatio(1.5)
            .borderRadius($r("app.float.radius_L"))
          TextBody1({text:'gif格式图片,rawfile目录'})
          Image($rawfile("ic_gif.gif")) // $rawfile资源要写文件后缀
            .width("100%")
            .aspectRatio(1.5)
            .borderRadius($r("app.float.radius_L"))
          TextBody1({text:'jpg格式图片,/common/images目录'})
          Image("/common/images/banner.jpg") // /common/images目录下的图片
            .width("100%")
            .aspectRatio(3.5)

在手机浅色模式和平板深色模式下效果如下:

3.3 Image组件和ImageAnimator组件-鸿蒙开发者社区

使用网络路径

如果图片来源于网络,接口还是和上面一样,但是需要在config.json文件中“js”节点的后面加入如下配置:

    "reqPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]

如下图所示:

3.3 Image组件和ImageAnimator组件-鸿蒙开发者社区

然后在ImageSample.ets页面加入如下代码:

          TextBody1({text:'svg格式图片,使用网络路径'})
          Image("https://developer.huawei.com/images/new-content/Navigation/HW-LOGO.svg") // 使用网络路径的图片
            .width(300).height(65) // Logo指定宽高,不进行自适应缩放

效果如下:

3.3 Image组件和ImageAnimator组件-鸿蒙开发者社区

2.属性

.alt(string | PixelMap): 加载时显示的占位图。支持本地图片和网络路径,支持使用媒体PixelMap对象。

示例代码:

          H8({text:'2.属性'})
          /**
           * .alt(string | PixelMap): 加载时显示的占位图。支持本地图片和网络路径,支持使用媒体PixelMap对象。
           */
          TextBody1({text:'.alt(string | PixelMap): 加载时显示的占位图'})
          Image('') // 这里使用网络路径的图片
            .width("100%")
            .aspectRatio(3.5)
            .alt($r('app.media.alt')) // 加载时显示的占位图

在媒体文件夹下放入alt.png图片,浅色模式和深色模式下效果如下:

3.3 Image组件和ImageAnimator组件-鸿蒙开发者社区

. objectFit (ImageFit): 设置图片的缩放类型。

示例代码:

          /**
           * .objectFit(ImageFit) 默认值Cover,设置图片的缩放类型。
           *    ImageFit.Cover 保持宽高比进行缩小或者放大,使得图片两边都大于或等于显示边界。
           *    ImageFit.Contain 保持宽高比进行缩小或者放大,使得图片完全显示在显示边界内。
           *    ImageFit.Fill 不保持宽高比进行放大缩小,使得图片填充满显示边界。
           *    ImageFit.None 保持原有尺寸显示。通常配合objectRepeat属性一起使用。
           *    ImageFit.ScaleDown 保持宽高比显示,图片缩小或者保持不变。
           */
          TextBody1({text:'.objectFit(ImageFit):设置图片的缩放类型'})
          Image($r("app.media.cover"))
            .width('100%').height(120)
            .objectFit(ImageFit.Cover)
          Image($r("app.media.cover"))
            .width('100%').height(120)
            .objectFit(ImageFit.Contain)
          Image($r("app.media.cover"))
            .width('100%').height(120)
            .objectFit(ImageFit.Fill)
          Image($r("app.media.cover"))
            .width('100%').height(120)
            .objectFit(ImageFit.None)
          Image($r("app.media.cover"))
            .width('100%').height(120)
            .objectFit(ImageFit.ScaleDown)

在手机和平板上,图片表现如下:

3.3 Image组件和ImageAnimator组件-鸿蒙开发者社区

. objectRepeat (ImageRepeat): 设置图片的重复样式。

示例代码:

          /**
           * .objectRepeat (ImageRepeat): 默认值NoRepeat,设置图片的重复样式。
           *    ImageRepeat.X 只在水平轴上重复绘制图片。
           *    ImageRepeat.Y 只在竖直轴上重复绘制图片。
           *    ImageRepeat.XY 在两个轴上重复绘制图片。
           *    ImageRepeat.NoRepeat 不重复绘制图片。
           * 注意:SVG类型图源不支持该属性。
           */
          TextBody1({text:'. objectRepeat (ImageRepeat): 设置图片的重复样式'})
          Image($r('app.media.icon'))
            .width(115).height(115)
            .border({ width: 1 }).borderStyle(BorderStyle.Dashed)
            .objectFit(ImageFit.ScaleDown)
            .objectRepeat(ImageRepeat.X) // 只在水平轴上重复绘制图片
          Image($r('app.media.icon'))
            .width(115).height(115)
            .border({ width: 1 }).borderStyle(BorderStyle.Dashed)
            .objectFit(ImageFit.ScaleDown)
            .objectRepeat(ImageRepeat.Y) // 只在竖直轴上重复绘制图片
          Image($r('app.media.icon'))
            .width(115).height(115)
            .border({ width: 1 }).borderStyle(BorderStyle.Dashed)
            .objectFit(ImageFit.ScaleDown)
            .objectRepeat(ImageRepeat.XY) // 在两个轴上重复绘制图片
          Image($r('app.media.icon'))
            .width(115).height(115)
            .border({ width: 1 }).borderStyle(BorderStyle.Dashed)
            .objectFit(ImageFit.ScaleDown)
            .objectRepeat(ImageRepeat.NoRepeat) // 不重复绘制图片

运行效果:

3.3 Image组件和ImageAnimator组件-鸿蒙开发者社区

. interpolation (ImageInterpolation): 设置图片的插值效果,仅针对图片放大插值。

对于一些较小的图片,或老照片,插值计算有助于提升画质。示例代码:

          /**
           * .interpolation (ImageInterpolation): 设置图片的插值效果,仅针对图片放大插值。默认值None。
           *    ImageInterpolation.None 不使用插值图片数据。
           *    ImageInterpolation.High 高度使用插值图片数据,可能会影响图片渲染的速度。
           *    ImageInterpolation.Medium 中度使用插值图片数据。
           *    ImageInterpolation.Low 低度使用插值图片数据。
           * 注意:SVG类型图源不支持该属性;PixelMap资源不支持该属性。
           */
		  TextBody1({text:'.interpolation (ImageInterpolation): 设置图片的插值效果'})
          Image('/common/images/photo.png')
            .width(300)
            .objectFit(ImageFit.Cover)
            .interpolation (ImageInterpolation.None) // 不使用插值图片数据
          Image('/common/images/photo.png')
            .width(300)
            .objectFit(ImageFit.Cover)
            .interpolation (ImageInterpolation.High) // 高度使用插值图片数据
          Image('/common/images/photo.png')
            .width(300)
            .objectFit(ImageFit.Cover)
            .interpolation (ImageInterpolation.Medium) // 中度使用插值图片数据
          Image('/common/images/photo.png')
            .width(300)
            .objectFit(ImageFit.Cover)
            .interpolation (ImageInterpolation.Low) // 低度使用插值图片数据

可以看到,原图放大后有马赛克,而高插值的方式就很平滑了。效果对比如下:

3.3 Image组件和ImageAnimator组件-鸿蒙开发者社区

. renderMode (ImageRenderMode): 设置图片渲染的模式。 相当于PS中对图片做去色处理,可将彩色图片变为灰度图片。

示例代码:

          /**
           * .renderMode(ImageRenderMode) 默认值Original,设置图片渲染的模式。
           *    ImageRenderMode.Original 按照原图进行渲染,包括颜色。
           *    ImageRenderMode.Template 将图像渲染为模板图像,忽略图片的颜色信息。
           * 注意:SVG类型图源不支持该属性。
           */
          TextBody1({text:'.renderMode(ImageRenderMode) 设置图片渲染的模式'})
          Image("/common/images/banner.jpg")
            .width("100%")
            .aspectRatio(3.5)
            .renderMode(ImageRenderMode.Original) // 按照原图进行渲染,包括颜色
          Image("/common/images/banner.jpg")
            .width("100%")
            .aspectRatio(3.5)
            .renderMode(ImageRenderMode.Template) // 忽略图片的颜色信息

效果如下:

3.3 Image组件和ImageAnimator组件-鸿蒙开发者社区

.sourceSize({width: number,height: number}): 设置图片解码尺寸,将原始图片解码成指定尺寸的图片,number类型单位为px。

一张原本尺寸为1200x750像素的图片,指定解码尺寸为150x100像素的照片后,如果图片展示尺寸超过该尺寸,就会模糊,示例代码如下:

          /**
           * .sourceSize({width: number,height: number}) 设置图片解码尺寸,将原始图片解码成指定尺寸的图片,number类型单位为px。
           * 注意:PixelMap资源不支持该属性。
           */
          TextBody1({text:'.sourceSize({width: number,height: number}) 设置图片解码尺寸'})
          Image($r("app.media.cover"))
            .borderRadius($r("app.float.radius_L"))
            .sourceSize({
              width: 150,
              height: 100
            }) // 解码为小尺寸后显示模糊
          Image($r("app.media.cover")) // 原图效果
            .borderRadius($r("app.float.radius_L"))

解码为小尺寸和原图的效果对比如下:

3.3 Image组件和ImageAnimator组件-鸿蒙开发者社区

对于.sourceSize属性的使用,我个人的看法是:如果原图较小,通过sourceSize解码为大尺寸,建议配合.interpolation (ImageInterpolation)属性来设置图片的插值,改善画质;如果原图较大,通过sourceSize解码为小尺寸,建议配合.objectFit(ImageFit.ScaleDown)属性显示为合适的尺寸,保证清晰度。

如有不同想法,欢迎留言讨论。

3.事件

1.onComplete(callback: (event?: { width: number, height: number, componentWidth: number, componentHeight: number, loadingStatus: number }) => void):图片成功加载时触发该回调,返回成功加载的图源尺寸。

2.onError(callback: (event?: { componentWidth: number, componentHeight: number }) => void):图片加载出现异常时触发该回调。

3.onFinish(callback: () => void) 当加载的源文件为带动效的svg图片时,当svg动效播放完成时会触发这个回调,如果动效为无限循环动效,则不会触发这个回调。

示例代码:

          /**
           * 事件:
           * 1.onComplete(callback: (event?: { width: number, height: number, componentWidth: number, componentHeight: number, loadingStatus: number }) => void):图片成功加载时触发该回调,返回成功加载的图源尺寸。
           * 2.onError(callback: (event?: { componentWidth: number, componentHeight: number }) => void):图片加载出现异常时触发该回调。
           * 3.onFinish(callback: () => void) 当加载的源文件为带动效的svg图片时,当svg动效播放完成时会触发这个回调,如果动效为无限循环动效,则不会触发这个回调。
           */
          H8({text:'3.事件'})
          Image("https://developer.huawei.com/images/new-content/Navigation/HW-LOGO.svg") // 使用网络路径的图片
            .width(300).height(65)
            .onComplete((msg: { width: number,height: number }) => {
              // 可根据 msg.width和 msg.height的大小决定卡片显示风格等
            })
            .onError(() => {
              console.log('加载图片失败')
            })
            .onFinish(() => {
              //
            })
4.图像效果

前面演示了通过Image组件的.renderMode(ImageRenderMode)实现图片的去色效果。在基于TS扩展的声明式开发范式中还有一些控制图像效果的属性,这些属性不仅可以用于Image组件,也可以用于其它组件。

示例代码如下:

          /**
           * 图像效果
           * 属性:
           *  blur:number 为当前组件添加内容模糊效果,入参为模糊半径,模糊半径越大越模糊,为0时不模糊。
           *  backdropBlur:number 为当前组件添加背景模糊效果,入参为模糊半径,模糊半径越大越模糊,为0时不模糊。
           *  shadow:{radius: number,color?: Color,offsetX?: number,offsetY?: number}
           *    为当前组件添加阴影效果,入参为模糊半径(必填)、阴影的颜色(可选,默认为灰色)、X轴的偏移量(可选,默认为0),Y轴的偏移量(可选,默认为0),偏移量单位为px。
           *  grayscale:number 默认值0.0,为当前组件添加灰度效果。值定义为灰度转换的比例,入参1.0则完全转为灰度图像,入参则0.0图像无变化,入参在0.0和1.0之间时,效果呈线性变化。(百分比)
           *  brightness:number 默认值1.0,为当前组件添加高光效果,入参为高光比例,值为1时没有效果,小于1时亮度变暗,0为全黑;大于1时亮度增加,数值越大亮度越大。
           *  saturate:number 默认值1.0,为当前组件添加饱和度效果,饱和度为颜色中的含色成分和消色成分(灰)的比例,入参为1时,显示原图像,大于1时含色成分越大,饱和度越大;小于1时消色成分越大,饱和度越小。(百分比)
           *  contrast:number 默认值1.0,为当前组件添加对比度效果,入参为对比度的值,值为1时,显示原图;大于1时,值越大对比度越高,图像越清晰醒目;小于1时,值越小对比度越低;当对比度为0时,图像变为全灰。(百分比)
           *  invert:number 默认值0,反转输入的图像。入参为图像反转的比例。值为1时完全反转。值为0则图像无变化。(百分比)
           *  sepia:number 默认值0,将图像转换为深褐色。入参为图像反转的比例。值为1则完全是深褐色的,值为0图像无变化。 (百分比)
           *  hueRotate:number 默认值0deg,为当前组件添加色相旋转效果,入参为旋转的角度值。当入参为0deg时图像无变化(默认值是0deg),入参没有最大值,超过360deg的值相当于又绕一圈。
           */
          H8({text:'4.图像效果'})
          TextBody1({text:'添加内容模糊效果'})
          Image("/common/images/banner.jpg") // /common/images目录下的图片
            .width("100%")
            .aspectRatio(3.5)
            .blur(3) // 为当前组件添加内容模糊效果

          TextBody1({text:'背景模糊效果'})
          Row().width('100%').height(240)
            .backgroundImage('/common/images/banner.jpg')
            .backgroundImageSize({ width: 1200, height: 800 })
            .backgroundImagePosition(Alignment.Center)
            .backdropBlur(3)

          TextBody1({text:'添加阴影效果'})
          Image("/common/images/banner.jpg").width('100%').aspectRatio(3.5)
            .shadow({ radius: 10, color: Color.Gray, offsetX: 5, offsetY: 5 })

          TextBody1({text:'添加灰度效果'})
          Image("/common/images/lake.jpg").width('100%').aspectRatio(3.5)
            .grayscale(0.6)

          TextBody1({text:'添加高光效果'})
          Image("/common/images/lake.jpg").width('100%').aspectRatio(3.5)
            .brightness(2.0)

          TextBody1({text:'添加饱和度效果'})
          Image("/common/images/lake.jpg").width('100%').aspectRatio(3.5)
            .saturate(2.0)

          TextBody1({text:'添加对比度效果'})
          Image("/common/images/lake.jpg").width('100%').aspectRatio(3.5)
            .contrast(2.0)

          TextBody1({text:'反转输入的图像'})
          Image("/common/images/lake.jpg").width('100%').aspectRatio(3.5)
            .invert(1)

          TextBody1({text:'图像转换为深褐色'})
          Image("/common/images/lake.jpg").width('100%').aspectRatio(3.5)
            .sepia(1)

          TextBody1({text:'色相旋转效果'})
          Image("/common/images/lake.jpg").width('100%').aspectRatio(3.5)
            .hueRotate(90)

上述代码的效果可以通过远程模拟器体验:

3.3 Image组件和ImageAnimator组件-鸿蒙开发者社区

5.共享元素转场

在图片列表页面给缩略图设置一个id,在放大显示图片的展示页也给图片设置一个相同的id, 利用共享元素转场,将当前页面的图片转场到详情页面。

属性:

. sharedTransition(id: string, options?: Object) : 两个页面的组件配置为同一个id,则转场过程中会进行共享元素转场,配置为空字符串时不会有共享元素转场效果。 其中options参数说明如下:

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

curve : Curve | Curves 默认曲线为线性

delay:number 默认值0,单位为毫秒,默认不延时播放。

示例代码:

首先在ImageSample.ets页面添加如下代码:

          /**
           * 5.共享元素转场
           * 共享元素转场支持页面间的转场,如当前页面的图片转场至下一页面中。
           *
           * 属性:
           *  .sharedTransition(id: string,options?: Object)
           *  两个页面的组件配置为同一个id,则转场过程中会进行共享元素转场,配置为空字符串时不会有共享元素转场效果。
           *    options参数说明:
           *    duration:number 默认值1000,单位为毫秒,默认动画时长为1000毫秒。
           *    curve:Curve | Curves 默认值Linear,默认曲线为线性
           *      Curve.Linear 表示动画从头到尾的速度都是相同的。
           *      Curve.Ease 表示动画以低速开始,然后加快,在结束前变慢,CubicBezier(0.25, 0.1, 0.25, 1.0)。
           *      Curve.EaseIn 表示动画以低速开始,CubicBezier(0.42, 0.0, 1.0, 1.0)。
           *      Curve.EaseOut 表示动画以低速结束,CubicBezier(0.0, 0.0, 0.58, 1.0)。
           *      Curve.EaseInOut 表示动画以低速开始和结束,CubicBezier(0.42, 0.0, 0.58, 1.0)。
           *      Curve.FastOutSlowIn 标准曲线,cubic-bezier(0.4, 0.0, 0.2, 1.0)。
           *      Curve.LinearOutSlowIn 减速曲线,cubic-bezier(0.0, 0.0, 0.2, 1.0)。
           *      Curve.FastOutLinearIn 加速曲线,cubic-bezier(0.4, 0.0, 1.0, 1.0)。
           *      Curve.ExtremeDeceleration 急缓曲线,cubic-bezier(0.0, 0.0, 0.0, 1.0)。
           *      Curve.Sharp 锐利曲线,cubic-bezier(0.33, 0.0, 0.67, 1.0)。
           *      Curve.Rhythm 节奏曲线,cubic-bezier(0.7, 0.0, 0.2, 1.0)。
           *      Curve.Smooth 平滑曲线,cubic-bezier(0.4, 0.0, 0.4, 1.0)。
           *      Curve.Friction 阻尼曲线,CubicBezier(0.2, 0.0, 0.2, 1.0)。
           *    delay:number 默认值0,单位为毫秒,默认不延时播放。
           */
          H8({text:'5.共享元素转场'})
          Navigator({ target: 'pages/ImageDetailSample', type: NavigationType.Push }) {
            Image($r("app.media.cover"))
              .width(100)
              .aspectRatio(1.5)
              .sharedTransition('sharedId1', { duration: 800, curve: Curve.Linear, delay: 100 })
          }

然后新建一个ImageDetailSample.ets页面,代码如下:

@Entry
@Component
struct ImageDetailSample {
  build() {
    Column({space:8}) {
      Navigator({ target: 'pages/ImageSample', type: NavigationType.Back }) {
        Image($r("app.media.cover"))
          .width("100%")
          .aspectRatio(1.5)
          .borderRadius($r("app.float.radius_L"))
          .sharedTransition('sharedId1') // 设置和上级页面相同的id
      }
    }
    .width('100%')
    .height('100%')
    .padding({top: $r("app.float.spaceTop"), bottom:$r("app.float.spaceBottom"), left:$r("app.float.spaceLeft"), right: $r("app.float.spaceRight")})
    .backgroundColor($r("app.color.appBg"))
  }
}

建议在DevEco Studioi中通过本地预览器或远程模拟器体验流畅的转场动画效果,可以点击放大,也可以点击返回上级页面时缩小,运行效果如下:

3.3 Image组件和ImageAnimator组件-鸿蒙开发者社区

3.3.3 ImageAnimator组件

在ArkUI eTS语言中,可通过Image组件展示gif动画,同时,提供了一个ImageAnimator组件,提供帧动画组件来实现逐帧播放图片的能力,可以配置需要播放的图片列表,每张图片可以配置时长。

新建ImageAnimatorSample.ets页面,初始化代码如下:

import {H8} from './index'

/**
 * 3.3.3 ImageAnimator组件
 */
@Entry
@Component
struct ImageDetailSample {
  build() {
    Column({space:8}) {
      // 返回首页
      Row({space:8}){
        Image($r("app.media.ic_back")).width(24).height(24)

        Navigator({ target: 'pages/index', type: NavigationType.Back }) {
          H8({text:'返回'})
        }
      }

      // TODO
    }
    .width('100%')
    .height('100%')
    .padding({top: $r("app.float.spaceTop"), bottom:$r("app.float.spaceBottom"), left:$r("app.float.spaceLeft"), right: $r("app.float.spaceRight")})
    .backgroundColor($r("app.color.appBg"))
    .alignItems(HorizontalAlign.Start)
  }
}
1.接口

ImageAnimator()

2.属性

.images(Array<{
src:string, //图片路径,图片格式为svg,png和jpg。
width?:Length, //图片宽度。
height?:Length, //图片高度。
top?:Length, //图片相对于组件左上角的纵向坐标。
left?:Length, //图片相对于组件左上角的横向坐标。
duration?:number //每一帧图片的播放时长,单位毫秒。
}>):设置图片帧信息集合。

.state(AnimationStatus):用于控制播放状态。

.duration(number):持续时间

.reverse(boolean):设置播放顺序。

.fixedSize(boolean):设置图片大小是否固定为组件大小。

.preDecode(number):是否启用预解码。

.fillMode(FillMode): 设置动画开始前和结束后的状态 。

.iterations(number): 默认播放一次,设置为-1时表示无限次播放。

3.事件

onStart() => void : 状态回调,动画开始播放时触发。

onPause() => void : 状态回调,动画暂停播放时触发。

onRepeat() => void : 状态回调,动画重新播放时触发。

onCancel() => void : 状态回调,动画取消播放时触发。

onFinish() => void : 状态回调,动画播放完成时触发。

示例代码如下:

首先,在代码"build(){"之前加入如下代码:

  @State state: AnimationStatus = AnimationStatus.Initial
  @State reverse: boolean = false
  @State iterations: number = 1

代码位置如下图所示:

3.3 Image组件和ImageAnimator组件-鸿蒙开发者社区

然后在"// TODO"处加入如下代码:

      /**
       * 1.接口:ImageAnimator()
       * 2.属性:
       *  images:Array<{
            src:string, //图片路径,图片格式为svg,png和jpg。
            width?:Length, //图片宽度。
            height?:Length, //图片高度。
            top?:Length, //图片相对于组件左上角的纵向坐标。
            left?:Length, //图片相对于组件左上角的横向坐标。
            duration?:number //每一帧图片的播放时长,单位毫秒。
          }> 设置图片帧信息集合。每一帧的帧信息包含图片路径、图片大小、图片位置和图片播放时长信息。
       *  state:AnimationStatus 默认值Initial,默认为初始状态,用于控制播放状态。
       *    AnimationStatus.Initial 动画初始状态。
       *    AnimationStatus.Running 动画处于播放状态。
       *    AnimationStatus.Paused 动画处于暂停状态。
       *    AnimationStatus.Stopped 动画处于停止状态。
       *  duration:number 默认值1000,单位为毫秒,默认时长为1000ms;duration为0时,不播放图片;值的改变只会在下一次循环开始时生效;当images中设置了单独的duration后,该属性设置无效。
       *  reverse:boolean 默认值false,设置播放顺序。false表示从第1张图片播放到最后1张图片; true表示从最后1张图片播放到第1张图片。
       *  fixedSize:boolean 默认值true,设置图片大小是否固定为组件大小。 true表示图片大小与组件大小一致,此时设置图片的width 、height 、top 和left属性是无效的。false表示每一张图片的 width 、height 、top和left属性都要单独设置。
       *  preDecode:number 默认值0,是否启用预解码,默认值为0,即不启用预解码,如该值设为2,则播放当前页时会提前加载后面两张图片至缓存以提升性能。
       *  fillMode:FillMode 默认值Forwards,设置动画开始前和结束后的状态,可选值参见FillMode说明。
       *    FillMode.None 播放完成后恢复初始状态。
       *    FillMode.Forwards 播放完成后保持动画结束时的状态。
       *    FillMode.Backwards 在animation-delay所指定的一段时间内,在动画显示之前,应用开始属性值。
       *    FillMode.Both 向前和向后填充模式都被应用。
       *  iterations:number 默认值1,默认播放一次,设置为-1时表示无限次播放。
       *
       * 3.事件:
       *  onStart() => void 状态回调,动画开始播放时触发。
       *  onPause() => void 状态回调,动画暂停播放时触发。
       *  onRepeat() => void 状态回调,动画重新播放时触发。
       *  onCancel() => void 状态回调,动画取消播放时触发。
       *  onFinish() => void 状态回调,动画播放完成时触发。
       */
      ImageAnimator()
        .images([
          {
            src: '/common/images/01.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/02.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/03.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/04.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/05.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/06.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/07.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/08.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/09.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/10.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/11.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          },
          {
            src: '/common/images/12.jpg',
            duration: 100,
            width: 300,
            height: 300,
            top: 0,
            left: 0
          }
        ]) // 设置图片帧信息集合
        .state(this.state) // 用于控制播放状态
        .reverse(this.reverse) // 设置播放顺序,
        .fixedSize(false) // 设置图片大小是否固定为组件大小
        .preDecode(2) // 是否启用预解码
        .fillMode(FillMode.None) // 设置动画开始前和结束后的状态
        .iterations(this.iterations) // 默认播放一次,设置为-1时表示无限次播放
        .width(300).height(300)
        .margin({top:100})
        .onStart(() => { // 状态回调,动画开始播放时触发
          console.info('动画开始播放')
        })
        .onPause(() => { // 状态回调,动画暂停播放时触发
          console.info('动画暂停播放')
        })
        .onRepeat(() => { // 状态回调,动画重新播放时触发
          console.info('动画重新播放')
        })
        .onCancel(() => { // 状态回调,动画取消播放时触发
          console.info('动画取消播放')
        })
        .onFinish(() => { // 状态回调,动画播放完成时触发
          console.info('动画播放完成')
        })
      Row() {
        Button('开始').width(100).padding(5).onClick(() => {
          this.state = AnimationStatus.Running
        })
        Button('暂停').width(100).padding(5).onClick(() => {
          this.state = AnimationStatus.Paused
        })
        Button('停止').width(100).padding(5).onClick(() => {
          this.state = AnimationStatus.Stopped
        })
      }
      Row() {
        Button('反向播放').width(100).padding(5).onClick(() => {
          this.reverse = !this.reverse
        })
        Button('播放一次').width(100).padding(5).onClick(() => {
          this.iterations = 1
        })
        Button('无限循环').width(100).padding(5).onClick(() => {
          this.iterations = -1
        })
      }

运行效果如下:

3.3 Image组件和ImageAnimator组件-鸿蒙开发者社区

【本节源码:https://gitee.com/cloudev/harmonyos3/tree/master/3.0/BaseComponent

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
5
收藏 2
回复
举报
2条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

赞,老师讲解的非常详细

1
回复
2022-6-1 10:07:57
物联风景
物联风景

点赞,收藏,评论三连

1
回复
2022-6-1 10:59:18
回复
    相关推荐