HarmonyOS 鸿蒙Next横屏

HarmonyOS 鸿蒙Next横屏 网络图片用Image组件加载变成横屏显示如何解决

3 回复

【背景知识】

  1. Exif(Exchangeable image file format 可交换图像文件格式),是一种图像文件格式,其数据存储与JPEG格式是完全相同的,EXIF可以附加于JPEG、TIFF、RIFF、RAW等文件之中,为其增加有关数码相机拍摄信息的内容和索引图或图像处理软件的版本信息。
  2. ImageSource.getImageProperty:可以通过该接口获取图片中给定索引处图像的指定属性键的值,仅支持JPEG、PNG和HEIF(不同硬件设备支持情况不同)文件,且需要包含Exif信息。其中可以通过supportedFormats属性查询是否支持HEIF格式的Exif读写。

【解决方案】

该问题的根本原因是图片里的Exif信息存在旋转90°的信息,HarmonyOS的Image组件会读取图片中的信息并旋转。如果不想旋转需要应用自行进行适配,目前可尝试如下以下方案适配:

  1. 由于Image组件无法拿到图片数据,需要先通过网络请求获取图片,设置传输数据类型expectDataType为arraybuffer,然后使用createImageSource转换成image.ImageSource对象;
  2. 获取图片Exif信息,可以通过getImageProperty接口 (PropertyKey传入"Orientation")获取旋转信息。通过判断图片是否要旋转,并将不同返回值的旋转角度返回给Image组件的rotate属性进行旋转;
  3. 若需要将网络图片保存至本地使用,可以下载网络图片获取图片数据后,通过imageSource.createPixelMap接口,转成PixelMap对象,最后将PixelMap对象的图片给到Image组件。

代码参考如下:

import { http } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { image } from '@kit.ImageKit';

@Entry
@Component
struct ImageExample2 {
  @State pixelMapImg: PixelMap | undefined = undefined;
  @State imageUrl: string = 'https://www.example.com/xxx.png'
  @State angel: number = 0;

  aboutToAppear() {
    this.requestImageUrl(this.imageUrl); // 请填写一个具体的网络图片地址
  }

  requestImageUrl(url: string) {
    http.createHttp().request(url,
      {
        expectDataType: http.HttpDataType.ARRAY_BUFFER
      },
      (error: BusinessError, data: http.HttpResponse) => {
      if (error) {
        console.error(`request image failed: url: ${url}, code: ${error.code}, message: ${error.message}`);
      } else {
        let imgData: ArrayBuffer = data.result as ArrayBuffer;
        console.info(`request image success, size: ${imgData.byteLength}`);
        let imgSource: image.ImageSource = image.createImageSource(imgData);
        imgSource.createPixelMap().then((pixelMap: PixelMap) => {
          imgSource.getImageProperty(image.PropertyKey.ORIENTATION).then((data:string)=>{
            console.info('image orientation data is',data)
            if (data === 'Right-top'){
              this.angel = 90;
            }
          })
          console.info('image createPixelMap success');
          this.pixelMapImg = pixelMap;
          imgSource.release();
        }).catch(() => {
          imgSource.release();
        })
      }
    })
  }

  build() {
    Column() {
      Image(this.imageUrl)
        .objectFit(ImageFit.None)
        .width('100%')
        .height('100%')
        .rotate({ angle: this.angel })
    }
  }
}

若需要下载图片后进行展示,可以通过downloadFile方法将图片下载到本地后,创建新PixelMap进行展示。

downloadImage(){
  let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
  let tempPath = context.filesDir + '/' + new Date().getTime() + '.jpeg';
  try {
    request.downloadFile(this.getUIContext().getHostContext(), {
      url: this.imageUrl,
      filePath: tempPath
    }).then((downloadTask: request.DownloadTask) => {
      downloadTask.on('complete', async () => {
        let file = fileIo.openSync(tempPath, fileIo.OpenMode.READ_ONLY);
        let imgSource: image.ImageSource = image.createImageSource(file.fd);
        imgSource.createPixelMap().then((pixelMap: PixelMap) => {
          imgSource.getImageProperty(image.PropertyKey.ORIENTATION).then((data: string) => {
            console.info('===', data)
            if (data === 'Right-top') {
              this.angel = 90;
            }
          })
          console.info('image createPixelMap success');
          this.pixelMapImg = pixelMap;
          imgSource.release();
        }).catch(() => {
          imgSource.release();
        })
      })
    })
  } catch (error) {
    console.error('download error',error)
  }
}

自API 14起,对于包含EXIF信息的图片可以通过设置图片的通用属性orientation为ImageRotateOrientation.AUTO,读取图片携带的EXIF元数据作为显示方向,支持旋转和镜像。

更多关于HarmonyOS 鸿蒙Next横屏的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


HarmonyOS Next横屏适配基于声明式UI开发范式。通过使用媒体查询接口检测屏幕方向变化,结合栅格系统和响应式布局能力实现横屏界面自适应。应用可使用窗口管理器接口监听屏幕旋转事件,动态调整组件布局和尺寸。鸿蒙系统提供了自适应布局能力和多种布局容器,确保横竖屏切换时界面元素自动重排。横屏模式下需注意导航栏、状态栏等系统组件的适配处理。

在HarmonyOS Next中,若Image组件加载网络图片时出现强制横屏显示,可通过以下方式解决:

  1. 设置图片方向约束 在Image组件添加layoutDirection属性限制方向:
Image($r('app.media.network_image'))
  .layoutDirection(LayoutDirection.LTR) // 强制左到右布局方向
  1. 使用媒体查询控制横竖屏 在entry/src/main/resources/base/media/路径下创建不同方向的布局文件:
  • 竖屏:media/width-300vp/布局文件
  • 横屏:media/height-300vp/布局文件
  1. 通过窗口管理器锁定方向 在Ability的onWindowStageCreate回调中设置:
windowClass.setPreferredOrientation(display.Orientation.PORTRAIT) // 锁定竖屏
  1. 图片解码时保留EXIF信息 使用ImageDecoder时配置参数:
let imageSource = image.createImageSource(uri)
let decodingOptions = {
  desiredSize: { width: 100, height: 100 },
  rotate: 0 // 明确指定旋转角度
}

建议同时检查图片源本身的EXIF方向信息,部分网络图片可能包含旋转元数据。可通过以上方法组合使用确保正确显示方向。

回到顶部