ts-basic-components-image.md 18.7 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
| interpolation         | [ImageInterpolation](#imageinterpolation)               | 设置图片的插值效果,即减轻低清晰度图片在放大显示的时候出现的锯齿问题,仅针对图片放大插值。<br/>默认值:ImageInterpolation.None<br/>**说明:**<br/>svg类型图源不支持该属性。<br/>PixelMap资源不支持该属性。 |
| renderMode            | [ImageRenderMode](#imagerendermode)                     | 设置图片渲染的模式。<br/>默认值:ImageRenderMode.Original<br/>**说明:**<br/>svg类型图源不支持该属性。 |
43
| sourceSize            | {<br/>width:&nbsp;number,<br/>height:&nbsp;number<br/>} | 设置图片裁剪尺寸,将原始图片解码成pixelMap,指定尺寸的图片,单位为px。<br/>**说明:**<br/>PixelMap资源和SVG图片不支持该属性。 |
G
gmy 已提交
44
| 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

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

57
### ImageInterpolation
Z
zengyawen 已提交
58

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

### ImageRenderMode

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

## 事件
Z
zengyawen 已提交
74

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

Y
yamila 已提交
77 78
| 名称                                                         | 功能描述                                                     |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
H
HelloCrease 已提交
79
| 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 已提交
80 81
| 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 已提交
82 83

## 示例
Z
zengyawen 已提交
84

85 86
### 图片加载

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

```ts
Z
zengyawen 已提交
90 91 92
@Entry
@Component
struct ImageExample1 {
Z
zengyawen 已提交
93
  private on: string = 'www.example.com' 
Z
zengyawen 已提交
94 95 96 97 98 99 100 101
  @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'))
102
            .width(110).height(110).border({ width: 1 })
Z
zengyawen 已提交
103 104
            .overlay('png', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
          Image($r('app.media.ic_gif'))
105
            .width(110).height(110).border({ width: 1 })
Z
zengyawen 已提交
106 107
            .overlay('gif', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
          Image($r('app.media.ic_svg'))
108
            .width(110).height(110).border({ width: 1 })
Z
zengyawen 已提交
109 110 111 112
            .overlay('svg', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
        }
        Row({ space: 5 }) {
          Image($r('app.media.img_example'))
113
            .width(110).height(110).border({ width: 1 })
Z
zengyawen 已提交
114 115
            .overlay('jpg', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
          Image(this.src)
116
            .width(110).height(110).border({ width: 1 })
Z
zengyawen 已提交
117 118 119 120 121 122 123 124
            .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'))
125
            .border({ width: 1 })
Z
zengyawen 已提交
126 127 128
            .objectFit(ImageFit.None).width(110).height(110)
            .overlay('None', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
          Image($r('app.media.img_example'))
129
            .border({ width: 1 })
Z
zengyawen 已提交
130 131 132
            .objectFit(ImageFit.Fill).width(110).height(110)
            .overlay('Fill', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
          Image($r('app.media.img_example'))
133
            .border({ width: 1 })
Z
zengyawen 已提交
134 135 136 137 138
            .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'))
139
            .border({ width: 1 })
Z
zengyawen 已提交
140 141 142
            .objectFit(ImageFit.Contain).width(110).height(110)
            .overlay('Contain', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
          Image($r('app.media.img_example_w250'))
143
            .border({ width: 1 })
Z
zengyawen 已提交
144 145 146 147 148 149 150 151 152
            .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 已提交
153
![zh-cn_image_0000001250492613](figures/zh-cn_image_0000001250492613.gif)
Z
zengyawen 已提交
154

155 156 157 158 159 160 161 162


### 网络图片

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

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


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

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

  // 网络图片请求方法
  private httpRequest() {
Y
yamila 已提交
190
    let httpRequest = http.createHttp()
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
	
    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 已提交
210
            console.log("response code: " + code)
211 212 213 214 215 216 217 218
          }
        }
      }
    )
  }
}
```

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

221 222 223
### 设置属性

```ts
Z
zengyawen 已提交
224 225 226 227 228 229 230 231 232 233
@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)
234
          .border({ width: 1 })
Z
zengyawen 已提交
235 236 237
          .overlay('Original', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
        Image($r('app.media.img_example'))
          .renderMode(ImageRenderMode.Template).width(100).height(100)
238
          .border({ width: 1 })
Z
zengyawen 已提交
239 240
          .overlay('Template', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
      }
241
      
Z
zengyawen 已提交
242 243 244
      Text('alt').fontSize(12).fontColor(0xcccccc).width('96%').height(30)
      Image('')
        .alt($r('app.media.Image_none'))
245
        .width(100).height(100).border({ width: 1 })
246
        
Z
zengyawen 已提交
247 248 249 250 251 252 253 254
      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)
255
          .border({ width: 1 })
Z
zengyawen 已提交
256 257 258 259 260 261 262
          .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)
263
          .border({ width: 1 })
Z
zengyawen 已提交
264 265
          .overlay('w:200 h:200', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
      }
266
      
Z
zengyawen 已提交
267 268 269
      Text('objectRepeat').fontSize(12).fontColor(0xcccccc).width('96%').height(30)
      Row({ space: 5 }) {
        Image($r('app.media.ic_health_heart'))
270
          .width(120).height(125).border({ width: 1 })
Z
zengyawen 已提交
271 272 273
          .objectRepeat(ImageRepeat.XY).objectFit(ImageFit.ScaleDown)
          .overlay('ImageRepeat.XY', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
        Image($r('app.media.ic_health_heart'))
274
          .width(110).height(125).border({ width: 1 })
Z
zengyawen 已提交
275 276 277
          .objectRepeat(ImageRepeat.Y).objectFit(ImageFit.ScaleDown)
          .overlay('ImageRepeat.Y', { align: Alignment.Bottom, offset: { x: 0, y: 20 } })
        Image($r('app.media.ic_health_heart'))
278
          .width(110).height(125).border({ width: 1 })
Z
zengyawen 已提交
279 280 281 282 283 284 285 286
          .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 已提交
287
![zh-cn_image_0000001205812616](figures/zh-cn_image_0000001205812616.png)
Z
zengyawen 已提交
288

289 290 291
### 事件调用

```ts
Z
zengyawen 已提交
292 293 294
@Entry
@Component
struct ImageExample3 {
T
tianyu 已提交
295 296
  @State widthValue: number = 0
  @State heightValue: number = 0
297 298 299 300
  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 已提交
301 302 303 304 305 306 307 308 309 310 311 312 313 314
  @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)
315
            // 图片加载完成后,获取图片尺寸。
Z
zengyawen 已提交
316
            .onComplete((msg: { width: number,height: number }) => {
T
tianyu 已提交
317 318
              this.widthValue = msg.width
              this.heightValue = msg.height
Z
zengyawen 已提交
319 320 321 322
            })
            .onError(() => {
              console.log('load image fail')
            })
323
            .overlay('\nwidth: ' + String(this.widthValue) + ' height: ' + String(this.heightValue), {
Z
zengyawen 已提交
324 325 326 327
              align: Alignment.Bottom,
              offset: { x: 0, y: 20 }
            })
        }
328
        // 为图片添加点击事件,点击完成后加载特定图片。
Z
zengyawen 已提交
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
        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 已提交
351
![zh-cn_image_0000001205972610](figures/zh-cn_image_0000001205972610.gif)
W
wangshuainan 已提交
352 353 354

###  渲染沙箱路径图片

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

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

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

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