ts-basic-components-image.md 18.8 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提供的图片路径。<br/>\- 支持file:///data/storage路径前缀的字符串,用于读取本应用安装目录下files文件夹下的图片资源。需要保证目录包路径下的文件有可读权限。 |
Z
zengyawen 已提交
31 32 33

## 属性

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

G
gmy 已提交
36 37
| 名称                  | 参数类型                                                | 描述                                                         |
| --------------------- | ------------------------------------------------------- | ------------------------------------------------------------ |
H
HelloCrease 已提交
38
| alt                   | string \| [Resource](ts-types.md#resource类型) | 加载时显示的占位图,支持本地图片和网络图片。                 |
G
gmy 已提交
39 40 41 42 43 44 45
| objectFit             | [ImageFit](ts-appendix-enums.md#imagefit)                           | 设置图片的缩放类型。<br/>默认值:ImageFit.Cover                  |
| objectRepeat          | [ImageRepeat](ts-appendix-enums.md#imagerepeat)         | 设置图片的重复样式。<br/>默认值:NoRepeat<br/>**说明:**<br/>svg类型图源不支持该属性。 |
| 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   |
| fitOriginalSize        | boolean | 图片组件尺寸未设置时,其显示尺寸是否跟随图源尺寸。<br/>默认值:true    |
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,即可实现点击获焦。
L
luoying_ace_admin 已提交
55
>  图片设置svg图源时,支持的标签范围有限,目前支持的svg标签包括svg、rect、circle、ellipse、path、line、polyline、polygon、animate、animateMotion、animateTransform。
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)外,还支持以下事件:

H
HelloCrease 已提交
77 78 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/> |
K
kangchongtao 已提交
80
| 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:组件的高,单位为像素。<br/> |
K
kangchongtao 已提交
81
| 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 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
  @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 已提交
153
![zh-cn_image_0000001250492613](figures/zh-cn_image_0000001250492613.gif)
Z
zengyawen 已提交
154

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218


### 网络图片

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

```tsx
// @ts-nocheck
import http from '@ohos.net.http';
import ResponseCode from '@ohos.net.http';
import image from '@ohos.multimedia.image'


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

  build() {
    Column({space: 10}) {
      Button("获取网络图片")
        .onClick(() => {
          this.httpRequest();
        })
      Image(this.image).height(100).width(100)
    }
    .width('100%')
    .height('100%')
    .padding(10)
  }

  // 网络图片请求方法
  private httpRequest() {
    let httpRequest = http.createHttp();
	
    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 {
            console.log("response code: " + code);
          }
        }
      }
    )
  }
}
```

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 234 235 236 237 238 239 240
@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 } })
      }
241
      
Z
zengyawen 已提交
242 243 244 245
      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)
246
        
Z
zengyawen 已提交
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
      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 } })
      }
266
      
Z
zengyawen 已提交
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
      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 已提交
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 323 324 325 326 327
            })
            .onError(() => {
              console.log('load image fail')
            })
            .overlay('\nwidth: ' + String(this.width) + ' height: ' + String(this.height), {
              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 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401

###  渲染沙箱路径图片

```
import fileio from '@ohos.fileio';
import image from '@ohos.multimedia.image';

const EMPTY_PATH = 'file://';

@Entry
@Component
struct LoadImageExample {
  @State fileContent: string = '';
  @State path: string = EMPTY_PATH;
  @State accountInfoHeadPic: any = '';

  build() {
    Column() {
      Button('读取沙箱图片')
        .margin({ bottom: 10 })
        .onClick(() => {
          try {
            this.path = EMPTY_PATH;
            let context = getContext(this);
            let path = context.getApplicationContext().filesDir + '/icon.png';
            console.log(`读取沙箱图片=========>${path}`);
            let fd = fileio.openSync(path, 0o100, 0o666);
            console.log(`create file========>${fd}`);
            let srcPath = context.bundleCodeDir + '/entry/resource/base/media/icon.png';
            fileio.copyFileSync(srcPath, path);
            console.log(`error:=============>${e.message}`);
          }
        })
      Button('读取资源图片')
        .margin({ bottom: 10 })
        .onClick(() => {
          this.path = EMPTY_PATH;
          this.path += getContext(this.bundleCodeDir + '/entry/resource/base/media/icon.png');
        })
      Text(`图片路径:${this.path}`)
        .fontSize(20)
        .margin({ bottom: 10 })
      Image(this.path)
        .width(100)
        .height(100)
    }
    .width('100%').height('100%')
  }
}
```