ts-basic-components-image.md 19.5 KB
Newer Older
Z
zengyawen 已提交
1 2
# Image

3
图片组件,支持本地图片和网络图片的渲染展示。
Z
zengyawen 已提交
4

5
> **说明:**
G
gmy 已提交
6
>
7
> 该组件从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
Z
zengyawen 已提交
8 9


H
HelloCrease 已提交
10
## 需要权限
Z
zengyawen 已提交
11

H
HelloCrease 已提交
12
使用网络图片时,需要申请权限ohos.permission.INTERNET。具体申请方式请参考[权限申请声明](../../security/accesstoken-guidelines.md)
Z
zengyawen 已提交
13

Z
zengyawen 已提交
14 15

## 子组件
Z
zengyawen 已提交
16 17 18



Z
zengyawen 已提交
19 20 21

## 接口

K
kukixi 已提交
22
Image(src: string | PixelMap | Resource)
Z
zengyawen 已提交
23

24
通过图片数据源获取图片,用于后续渲染展示。
Z
zengyawen 已提交
25

26 27
**参数:** 

G
gmy 已提交
28 29
| 参数名 | 参数类型                                                     | 必填 | 参数描述                                                     |
| ------ | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ |
Y
yamila 已提交
30
| src    | string\|&nbsp;[PixelMap](../apis/js-apis-image.md#pixelmap7)&nbsp;\|&nbsp;[Resource](ts-types.md#resource类型) | 是   | 图片的数据源,支持本地图片和网络图片。<br/>当使用相对路径引用图片资源时,例如`Image("common/test.jpg")`,不支持跨包/跨模块调用该Image组件,建议使用`$r`方式来管理需全局使用的图片资源。<br/>\- 支持的图片格式包括png、jpg、bmp、svg和gif。<br/>\- 支持`Base64`字符串。格式`data:image/[png\|jpeg\|bmp\|webp];base64,[base64 data]`, 其中`[base64 data]``Base64`字符串数据。<br/>\- 支持`datashare://`路径前缀的字符串,用于访问通过data&nbsp;ability提供的图片路径。图片加载前需要申请[媒体库功能相关权限](../../file-management/medialibrary-overview.md#申请媒体库功能相关权限)<br/>\- 支持file:///data/storage路径前缀的字符串,用于读取本应用安装目录下files文件夹下的图片资源。需要保证目录包路径下的文件有可读权限。 |
Z
zengyawen 已提交
31 32 33

## 属性

34 35
除支持[通用属性](ts-universal-attributes-size.md)外,还支持以下属性:

G
gmy 已提交
36 37
| 名称                  | 参数类型                                                | 描述                                                         |
| --------------------- | ------------------------------------------------------- | ------------------------------------------------------------ |
38
| alt                   | string \| [Resource](ts-types.md#resource类型) | 加载时显示的占位图,支持本地图片。                 |
G
gmy 已提交
39
| objectFit             | [ImageFit](ts-appendix-enums.md#imagefit)                           | 设置图片的缩放类型。<br/>默认值:ImageFit.Cover                  |
40
| objectRepeat          | [ImageRepeat](ts-appendix-enums.md#imagerepeat)         | 设置图片的重复样式。<br/>默认值:ImageRepeat.NoRepeat<br/>**说明:**<br/>svg类型图源不支持该属性。 |
G
gmy 已提交
41 42 43 44
| interpolation         | [ImageInterpolation](#imageinterpolation)               | 设置图片的插值效果,即减轻低清晰度图片在放大显示的时候出现的锯齿问题,仅针对图片放大插值。<br/>默认值:ImageInterpolation.None<br/>**说明:**<br/>svg类型图源不支持该属性。<br/>PixelMap资源不支持该属性。 |
| renderMode            | [ImageRenderMode](#imagerendermode)                     | 设置图片渲染的模式。<br/>默认值:ImageRenderMode.Original<br/>**说明:**<br/>svg类型图源不支持该属性。 |
| sourceSize            | {<br/>width:&nbsp;number,<br/>height:&nbsp;number<br/>} | 设置图片裁剪尺寸,将原始图片解码成pixelMap,指定尺寸的图片,单位为px。<br/>**说明:**<br/>PixelMap资源不支持该属性。 |
| matchTextDirection     | boolean | 设置图片是否跟随系统语言方向,在RTL语言环境下显示镜像翻转显示效果。<br/>默认值:false   |
45
| fitOriginalSize        | boolean | 图片组件尺寸未设置时,其显示尺寸是否跟随图源尺寸。<br/>默认值:false    |
L
luoying_ace_admin 已提交
46
| fillColor              | [ResourceColor](ts-types.md#resourcecolor) | 填充颜色。设置的填充颜色会覆盖在图片上。仅对svg图源生效,设置后会替换svg图片的fill颜色。 |
G
gmy 已提交
47 48 49
| autoResize             | boolean | 是否需要在图片解码过程中对图源做resize操作,该操作会根据显示区域的尺寸决定用于绘制的图源尺寸,有利于减少内存占用。<br/>默认值:true |
| syncLoad<sup>8+</sup> | boolean                                  | 设置是否同步加载图片,默认是异步加载。同步加载时阻塞UI线程,不会显示占位图。<br/>默认值:false |
| copyOption<sup>9+</sup> | [CopyOptions](ts-appendix-enums.md#copyoptions9)  | 设置图片是否可复制(SVG图片不支持复制)。<br/>当copyOption设置为非CopyOptions.None时,支持使用长按、鼠标右击、快捷组合键'CTRL+C'等方式进行复制。<br/>默认值:CopyOptions.None |
H
HelloCrease 已提交
50
| colorFilter<sup>9+</sup> | [ColorFilter](ts-types.md#colorfilter9) | 给图像设置颜色滤镜效果。 |
51
| draggable<sup>9+</sup> | boolean | 设置默认拖拽效果。(不能和[onDragStart](ts-universal-events-drag-drop.md)事件同时使用。)<br/>默认值:false |
52

B
bixuefeng 已提交
53
>  **说明:**
G
gmy 已提交
54
>
B
bixuefeng 已提交
55
>  使用快捷组合键对Image组件复制的前提是,该组件必须处于获焦状态。将Image组件的属性focusable设置为true,即可使用TAB键将焦点切换到Image组件上,再将Image组件的focusOnTouch属性设置为true,即可实现点击获焦。
L
luoying_ace_admin 已提交
56
>  图片设置svg图源时,支持的标签范围有限,目前支持的svg标签包括svg、rect、circle、ellipse、path、line、polyline、polygon、animate、animateMotion、animateTransform。
B
bixuefeng 已提交
57

58
### ImageInterpolation
Z
zengyawen 已提交
59

H
HelloCrease 已提交
60 61 62 63 64 65
| 名称     | 描述                        |
| ------ | ------------------------- |
| None   | 不使用插值图片数据。                |
| High   | 插值图片数据的使用率高,可能会影响图片渲染的速度。 |
| Medium | 插值图片数据的使用率中。              |
| Low    | 插值图片数据的使用率低。              |
66 67 68

### ImageRenderMode

H
HelloCrease 已提交
69 70 71
| 名称       | 描述                    |
| -------- | --------------------- |
| Original | 按照原图进行渲染,包括颜色。        |
72 73 74
| Template | 将图片渲染为模板图片,忽略图片的颜色信息。 |

## 事件
Z
zengyawen 已提交
75

76 77
除支持[通用事件](ts-universal-events-click.md)外,还支持以下事件:

Y
yamila 已提交
78 79
| 名称                                                         | 功能描述                                                     |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
H
HelloCrease 已提交
80
| onComplete(callback:&nbsp;(event?:&nbsp;{&nbsp;width:&nbsp;number,&nbsp;height:&nbsp;number,&nbsp;componentWidth:&nbsp;number,<br>&nbsp;componentHeight:&nbsp;number,&nbsp;loadingStatus:&nbsp;number&nbsp;})&nbsp;=&gt;&nbsp;void) | 图片成功加载时触发该回调,返回成功加载的图片尺寸。<br>- width:图片的宽,单位为像素。<br/>- height:图片的高,单位为像素。<br/>- componentWidth:组件的宽,单位为像素。<br/>- componentHeight:组件的高,单位为像素。<br/>- loadingStatus:图片加载成功的状态。<br/> |
Y
yamila 已提交
81 82
| onError(callback:&nbsp;(event?:&nbsp;{&nbsp;componentWidth:&nbsp;number,&nbsp;componentHeight:&nbsp;number&nbsp;, message<sup>9+</sup>: string })&nbsp;=&gt;&nbsp;void) | 图片加载出现异常时触发该回调。<br>- componentWidth:组件的宽,单位为像素。<br/>- componentHeight:组件的高,单位为像素。 |
| onFinish(event:&nbsp;()&nbsp;=&gt;&nbsp;void)                | 当加载的源文件为带动效的svg图片时,当svg动效播放完成时会触发这个回调,如果动效为无限循环动效,则不会触发这个回调。 |
Z
zengyawen 已提交
83 84

## 示例
Z
zengyawen 已提交
85

86 87
### 图片加载

88
加载显示不同类型的图片,并设置图片的缩放类型。
89 90

```ts
Z
zengyawen 已提交
91 92 93
@Entry
@Component
struct ImageExample1 {
Z
zengyawen 已提交
94
  private on: string = 'www.example.com' 
Z
zengyawen 已提交
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
  @State src: string = this.on

  build() {
    Column() {
      Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start }) {
        Text('default').fontSize(16).fontColor(0xcccccc).height(30)
        Row({ space: 5 }) {
          Image($r('app.media.ic_png'))
            .width(110).height(110).border({ width: 1 }).borderStyle(BorderStyle.Dashed)
            .overlay('png', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
          Image($r('app.media.ic_gif'))
            .width(110).height(110).border({ width: 1 }).borderStyle(BorderStyle.Dashed)
            .overlay('gif', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
          Image($r('app.media.ic_svg'))
            .width(110).height(110).border({ width: 1 }).borderStyle(BorderStyle.Dashed)
            .overlay('svg', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
        }
        Row({ space: 5 }) {
          Image($r('app.media.img_example'))
            .width(110).height(110).border({ width: 1 }).borderStyle(BorderStyle.Dashed)
            .overlay('jpg', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
          Image(this.src)
            .width(110).height(110).border({ width: 1 }).borderStyle(BorderStyle.Dashed)
            .overlay('network', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
        }.margin({ top: 25, bottom: 10 })
      }

      Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start }) {
        Text('objectFit').fontSize(16).fontColor(0xcccccc).height(30)
        Row({ space: 5 }) {
          Image($r('app.media.img_example'))
            .border({ width: 1 }).borderStyle(BorderStyle.Dashed)
            .objectFit(ImageFit.None).width(110).height(110)
            .overlay('None', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
          Image($r('app.media.img_example'))
            .border({ width: 1 }).borderStyle(BorderStyle.Dashed)
            .objectFit(ImageFit.Fill).width(110).height(110)
            .overlay('Fill', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
          Image($r('app.media.img_example'))
            .border({ width: 1 }).borderStyle(BorderStyle.Dashed)
            .objectFit(ImageFit.Cover).width(110).height(110)
            .overlay('Cover', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
        }
        Row({ space: 5 }) {
          Image($r('app.media.img_example_w250'))
            .border({ width: 1 }).borderStyle(BorderStyle.Dashed)
            .objectFit(ImageFit.Contain).width(110).height(110)
            .overlay('Contain', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
          Image($r('app.media.img_example_w250'))
            .border({ width: 1 }).borderStyle(BorderStyle.Dashed)
            .objectFit(ImageFit.ScaleDown).width(110).height(110)
            .overlay('ScaleDown', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
        }.margin({ top: 25 })
      }
    }.height(320).width(360).padding({ right: 10, top: 10 })
  }
}
```

Z
zengyawen 已提交
154
![zh-cn_image_0000001250492613](figures/zh-cn_image_0000001250492613.gif)
Z
zengyawen 已提交
155

156 157 158 159 160 161 162 163 164


### 网络图片

加载网络图片时,默认网络超时是5分钟,建议使用alt配置加载时的占位图。如果需要更灵活的网络配置,可以使用SDK中提供的[HTTP](../../connectivity/http-request.md)工具包发送网络请求,接着将返回的数据解码为Image组件中的`PixelMap`,图片开发可参考[图片处理](../../media/image.md)。代码如下。

```tsx
// @ts-nocheck
import http from '@ohos.net.http';
Y
yamila 已提交
165
import ResponseCode from '@ohos.net.http'
166 167 168 169 170 171 172 173 174 175 176 177 178 179
import image from '@ohos.multimedia.image'


@Entry 
@Component 
struct Index {
    
  // 先创建一个PixelMap状态变量用于接收网络图片
  @State image: PixelMap = undefined

  build() {
    Column({space: 10}) {
      Button("获取网络图片")
        .onClick(() => {
Y
yamila 已提交
180
          this.httpRequest()
181 182 183 184 185 186 187 188 189 190
        })
      Image(this.image).height(100).width(100)
    }
    .width('100%')
    .height('100%')
    .padding(10)
  }

  // 网络图片请求方法
  private httpRequest() {
Y
yamila 已提交
191
    let httpRequest = http.createHttp()
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
	
    httpRequest.request(
      "https://www.example.com/xxx.png",   // 请填写一个具体的网络图片地址
      (error, data) => {
        if(error) {
          console.log("error code: " + error.code + ", msg: " + error.message)
        } else {
          let code = data.responseCode
          if(ResponseCode.ResponseCode.OK == code) {
            let imageSource = image.createImageSource(data.result)
            let options = {alphaType: 0,                     // 透明度
                           editable: false,                  // 是否可编辑
                           pixelFormat: 3,                   // 像素格式
                           scaleMode: 1,                     // 缩略值
                           size: {height: 100, width: 100}}  // 创建图片大小
            imageSource.createPixelMap(options).then((pixelMap) => {
              this.image = pixelMap
            })
          } else {
Y
yamila 已提交
211
            console.log("response code: " + code)
212 213 214 215 216 217 218 219
          }
        }
      }
    )
  }
}
```

220
**说明**:网络图片加载的请求方式、超时、额外请求参数等配置可以参考HTTP工具包中关于[`request()`](../../reference/apis/js-apis-http.md)请求方法的细节。
221

222 223 224
### 设置属性

```ts
Z
zengyawen 已提交
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
@Entry
@Component
struct ImageExample2 {

  build() {
    Column({ space: 10 }) {
      Text('renderMode').fontSize(12).fontColor(0xcccccc).width('96%').height(30)
      Row({ space: 50 }) {
        Image($r('app.media.img_example'))
          .renderMode(ImageRenderMode.Original).width(100).height(100)
          .border({ width: 1 }).borderStyle(BorderStyle.Dashed)
          .overlay('Original', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
        Image($r('app.media.img_example'))
          .renderMode(ImageRenderMode.Template).width(100).height(100)
          .border({ width: 1 }).borderStyle(BorderStyle.Dashed)
          .overlay('Template', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
      }
242
      
Z
zengyawen 已提交
243 244 245 246
      Text('alt').fontSize(12).fontColor(0xcccccc).width('96%').height(30)
      Image('')
        .alt($r('app.media.Image_none'))
        .width(100).height(100).border({ width: 1 }).borderStyle(BorderStyle.Dashed)
247
        
Z
zengyawen 已提交
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
      Text('sourceSize').fontSize(12).fontColor(0xcccccc).width('96%')
      Row({ space: 50 }) {
        Image($r('app.media.img_example'))
          .sourceSize({
            width: 150,
            height: 150
          })
          .objectFit(ImageFit.ScaleDown).width('25%').aspectRatio(1)
          .border({ width: 1 }).borderStyle(BorderStyle.Dashed)
          .overlay('w:150 h:150', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
        Image($r('app.media.img_example'))
          .sourceSize({
            width: 200,
            height: 200
          })
          .objectFit(ImageFit.ScaleDown).width('25%').aspectRatio(1)
          .border({ width: 1 }).borderStyle(BorderStyle.Dashed)
          .overlay('w:200 h:200', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
      }
267
      
Z
zengyawen 已提交
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
      Text('objectRepeat').fontSize(12).fontColor(0xcccccc).width('96%').height(30)
      Row({ space: 5 }) {
        Image($r('app.media.ic_health_heart'))
          .width(120).height(125).border({ width: 1 }).borderStyle(BorderStyle.Dashed)
          .objectRepeat(ImageRepeat.XY).objectFit(ImageFit.ScaleDown)
          .overlay('ImageRepeat.XY', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
        Image($r('app.media.ic_health_heart'))
          .width(110).height(125).border({ width: 1 }).borderStyle(BorderStyle.Dashed)
          .objectRepeat(ImageRepeat.Y).objectFit(ImageFit.ScaleDown)
          .overlay('ImageRepeat.Y', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
        Image($r('app.media.ic_health_heart'))
          .width(110).height(125).border({ width: 1 }).borderStyle(BorderStyle.Dashed)
          .objectRepeat(ImageRepeat.X).objectFit(ImageFit.ScaleDown)
          .overlay('ImageRepeat.X', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
      }
    }.height(150).width('100%').padding({ right: 10 })
  }
}
```

Z
zengyawen 已提交
288
![zh-cn_image_0000001205812616](figures/zh-cn_image_0000001205812616.png)
Z
zengyawen 已提交
289

290 291 292
### 事件调用

```ts
Z
zengyawen 已提交
293 294 295
@Entry
@Component
struct ImageExample3 {
T
tianyu 已提交
296 297
  @State widthValue: number = 0
  @State heightValue: number = 0
298 299 300 301
  private on: Resource = $r('app.media.image_on')
  private off: Resource = $r('app.media.image_off')
  private on2off: Resource = $r('app.media.image_on2off')
  private off2on: Resource = $r('app.media.image_off2on')
Z
zengyawen 已提交
302 303 304 305 306 307 308 309 310 311 312 313 314 315
  @State src: Resource = this.on

  build() {
    Column() {
      Row({ space: 20 }) {
        Column() {
          Image($r('app.media.img_example1'))
            .alt($r('app.media.ic_public_picture'))
            .sourceSize({
              width: 900,
              height: 900
            })
            .objectFit(ImageFit.Cover)
            .height(180).width(180)
316
            // 图片加载完成后,获取图片尺寸。
Z
zengyawen 已提交
317
            .onComplete((msg: { width: number,height: number }) => {
T
tianyu 已提交
318 319
              this.widthValue = msg.width
              this.heightValue = msg.height
Z
zengyawen 已提交
320 321 322 323
            })
            .onError(() => {
              console.log('load image fail')
            })
324
            .overlay('\nwidth: ' + String(this.widthValue) + ' height: ' + String(this.heightValue), {
Z
zengyawen 已提交
325 326 327 328
              align: Alignment.Bottom,
              offset: { x: 0, y: 20 }
            })
        }
329
        // 为图片添加点击事件,点击完成后加载特定图片。
Z
zengyawen 已提交
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
        Image(this.src)
          .width(120).height(120)
          .onClick(() => {
            if (this.src == this.on || this.src == this.off2on) {
              this.src = this.on2off
            } else {
              this.src = this.off2on
            }
          })
          .onFinish(() => {
            if (this.src == this.off2on) {
              this.src = this.on
            } else {
              this.src = this.off
            }
          })
      }
    }.width('100%')
  }
}
```

Z
zengyawen 已提交
352
![zh-cn_image_0000001205972610](figures/zh-cn_image_0000001205972610.gif)
W
wangshuainan 已提交
353 354 355

###  渲染沙箱路径图片

Y
yamila 已提交
356
```ts
Y
yamila 已提交
357
import fileio from '@ohos.fileio'
Y
yamila 已提交
358
import fs from '@ohos.file.fs'
Y
yamila 已提交
359
import context from '@ohos.application.context'
W
wangshuainan 已提交
360 361 362 363

@Entry
@Component
struct LoadImageExample {
Y
yamila 已提交
364 365 366 367 368 369 370
  @State resourcesPath: string = ''
  @State sandboxPath: string = ''
  context: context.AbilityContext

  aboutToAppear() {
    this.context = getContext(this) as context.AbilityContext
  }
W
wangshuainan 已提交
371 372 373 374

  build() {
    Column() {
      Button('读取沙箱图片')
Y
yamila 已提交
375
        .margin({ bottom: 10, top: 10 })
W
wangshuainan 已提交
376
        .onClick(() => {
Y
yamila 已提交
377 378
          this.sandboxPath = this.context.getApplicationContext().filesDir + '/icon.png'
          console.log(`读取沙箱图片=========>${this.sandboxPath}`)
Y
yamila 已提交
379
          let fd = fs.openSync(this.sandboxPath, 0o100)
Y
yamila 已提交
380 381 382 383 384
          console.log(`create file========>${fd}`)
          let srcPath = this.context.bundleCodeDir + '/entry/resources/base/media/icon.png'
          console.log('mySrcpath' + srcPath)
          fileio.copyFileSync(srcPath, this.sandboxPath) // 复制图片到沙箱路径
          this.sandboxPath = 'file://' + this.context.getApplicationContext().filesDir + '/icon.png'
W
wangshuainan 已提交
385 386 387 388
        })
      Button('读取资源图片')
        .margin({ bottom: 10 })
        .onClick(() => {
Y
yamila 已提交
389
          this.resourcesPath = 'file://' + this.context.bundleCodeDir + '/entry/resources/base/media/icon.png'
W
wangshuainan 已提交
390
        })
Y
yamila 已提交
391 392 393 394 395 396 397
      Text(`资源图片路径:${this.resourcesPath}`)
        .fontSize(20)
        .margin({ bottom: 10 })
      Image(this.resourcesPath)
        .width(100)
        .height(100)
      Text(`沙箱图片路径:${this.sandboxPath}`)
W
wangshuainan 已提交
398 399
        .fontSize(20)
        .margin({ bottom: 10 })
Y
yamila 已提交
400
      Image(this.sandboxPath)
W
wangshuainan 已提交
401 402 403 404 405 406
        .width(100)
        .height(100)
    }
    .width('100%').height('100%')
  }
}
407
```