实现一个HarmonyOS 鸿蒙Next ImagePreview的功能

发布于 1周前 作者 vueper 来自 鸿蒙OS

实现一个HarmonyOS 鸿蒙Next ImagePreview的功能

实现一个 ImagePreview

简介

web 前端转鸿蒙总会有些编码习惯,比如vant组件库中提供的 ImagePreview 能力,可以在逻辑中直接进行调用,不需要我们维护一个图片预览组件,所以有需求就实现一个 ImagePreview

ps: 通过创建一个静态资源共享包来组织代码更好

通常的实现

@Component
struct Index {
    dialoag = new CustomDialogController({
        builder: ImagePreview({
          url: ['xxx'],
          currentUrl: 'xxx'
        }),
        customStyle: true
    })
    
    ...
    
    onClick() {
        this.dialog.open()
    }
}

使用 ImagePreview 实现

import {ImagePreview} from '...'
@Component
struct Index {
    onClick() {
        ImagePreview({
            url: ['xxx'],
            currentUrl: 'xxx'
        })
    }
}

实现思路

  1. window.createWindow 可以创建一个子窗口
  2. 使用子窗口 loadContentByName 加载一个命名路由页面
  3. loadContentByName 加载页面中给页面注入一个 LocalStorage
  4. 页面读取 LocalStorage 渲染下图片预览
  5. 点击关闭按钮销毁子窗口

具体代码

组件封装

import {IImagePreview, ROUTENAME, IMAGE_PREVIEW_WINDOW_NAME, ImagePreview} from './index'
@Entry({
    routeName: ROUTENAME,
    storage: LocalStorage.getShared()
})
@Component
export struct imagePreviewComp {
    @LocalStorageProp(IMAGE_PREVIEW_WINDOW_NAME) preview: IImagePreview = {
        urls: [
        ],
        currentUrl: '',
    }

    getIndex(): number {
        const r = this.preview.urls.findIndex(url => url === this.preview.currentUrl)
        return r > -1 ? r : 0
    }

    build() {
        Stack({
            alignContent: Alignment.TopEnd
        }) {
            Column() {
                Swiper() {
                    ForEach(this.preview.urls, (url: string) => {
                        Image(url)
                            .width('100%')
                            .height('100%')
                            .objectFit(ImageFit.Contain)
                    })
                }
                .index(this.getIndex())
                .width('80%')
                .height('80%')
                .indicator(false)
            }
            .width('100%')
            .height('100%')
            .justifyContent(FlexAlign.Center)

            // 关闭按钮
            Image($r('app.media.guanbi'))
                .width(30)
                .aspectRatio(1)
                .onClick(() => {
                    ImagePreview.close()
                })
                .margin({
                    top: 30,
                    right: 30
                })
        }
        .width('100%')
        .height('100%')
        .onClick(() => {
            ImagePreview.close()
        })
    }
}

调用函数的封装

// index.ets
import { window } from '@kit.ArkUI'
import { Context } from '@kit.AbilityKit';
// 导入图片预览组件
import('./ImagePreview');

export const ROUTENAME = 'imagePreview'
export const IMAGE_PREVIEW_WINDOW_NAME = 'imagePreview'
export interface IImagePreview {
    currentUrl: ResourceStr
    urls: ResourceStr[]
}

export class ImagePreview {
    static imagePreviewWindow: window.Window | null
    private static windowName = IMAGE_PREVIEW_WINDOW_NAME
    private static context: Context | null

    static async initContext(context: Context) {
        if (!ImagePreview.context) {
            ImagePreview.context = context
        }
        return ImagePreview.context
    }

    static async getImagePreviewWindow() {
        if (!ImagePreview.imagePreviewWindow) {
            if (ImagePreview.context) {
                const r = await window.createWindow({
                    name: ImagePreview.windowName,
                    windowType: window.WindowType.TYPE_DIALOG,
                    ctx: ImagePreview.context
                })
                ImagePreview.imagePreviewWindow = r
            } else {
                console.log(`create 阶段初始化下 context 使用 ImagePreview.initContext(this.context)`)
            }
        }
        return ImagePreview.imagePreviewWindow
    }

    static async open(config: IImagePreview) {
        try {
            const imagePreviewWindow = await ImagePreview.getImagePreviewWindow()
            if (imagePreviewWindow) {
                let storage: LocalStorage = new LocalStorage();
                storage.setOrCreate<IImagePreview>(IMAGE_PREVIEW_WINDOW_NAME, config)
                imagePreviewWindow.setWindowLayoutFullScreen(true)
                await imagePreviewWindow.loadContentByName('imagePreview', storage)
                imagePreviewWindow.setWindowBackgroundColor('#aa000000')
                imagePreviewWindow.showWindow()
                imagePreviewWindow.on('windowVisibilityChange', (visibility) => {
                    console.log('[预览图片窗口展示状态]', visibility)
                })
            }
        }
        catch (e) {
            console.log('[加载内容出错]', JSON.stringify(e))
        }
    }

    static async close() {
        const imagePreviewWindow = await ImagePreview.getImagePreviewWindow()
        if (imagePreviewWindow) {
            ImagePreview.imagePreviewWindow = null
            return imagePreviewWindow.destroyWindow()
        }
    }
}

使用

  1. 在 ability 的生命周期里初始化 context
import { ImagePreview } from 'JImagePreview'
export default class EntryAbility extends UIAbility {
    onCreate() {
        // 初始化 context
        ImagePreview.initContext(this.context)
    }
}
  1. 使用
import { ImagePreview } from 'JImagePreview'

@Entry
@Component
struct Index {
  image: string[] = [
    'http://192.168.0.200:8000/images/1.webp',
    'http://192.168.0.200:8000/images/2.webp',
    'http://192.168.0.200:8000/images/3.webp',
    'http://192.168.0.200:8000/images/4.webp',
    'http://192.168.0.200:8000/images/5.webp',
    'http://192.168.0.200:8000/images/6.webp',
  ]

  previewImage(url: string) {
    ImagePreview.open({
      currentUrl: url,
      urls: this.image,
    })
  }

  build() {
    Grid() {
      ForEach(this.image, (url: string) => {
        GridItem() {
          Image(url)
            .width('100%')
            .aspectRatio(1)
        }
        .onClick(() => {
          this.previewImage(url)
        })
      })
    }
    .columnsTemplate('1fr '.repeat(2))
  }
}

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

5 回复
补充个效果

![aaaa.gif](https://alliance-communityfile-drcn.dbankcdn.com/FileServer/getFile/cmtybbs/308/650/922/0070086000308650922.20240523173951.56483914054529842300171354324977:50001231000000:2800:EB813C4C2BB115B1F4853138CDF0A5CBFE9FE9A923F5F78805196AB7B942C4A2.gif)

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


这是用的API 9,思路挺好的

API 11里有段代码不支持,需要把

const r = this.preview.urls.findIndex(url => url === this.preview.currentUrl)

替换

let r = -1;
for (let i = 0; i < this.preview.urls.length; i++) {
  if (this.preview.urls[i] === this.preview.currentUrl) {
    r = i;
    break;
  }
}

嗯,没补充 api 版本,是该兼容下,感谢,

在HarmonyOS中实现一个ImagePreview功能,可以通过使用Image组件和PageSlider组件来实现。首先,使用Image组件来显示图片,然后通过PageSlider组件来实现图片的滑动预览。以下是一个简单的实现示例:

import { Image, PageSlider } from '@ohos.arkui';

@Entry
@Component
struct ImagePreview {
  private images: string[] = [
    'common/images/image1.jpg',
    'common/images/image2.jpg',
    'common/images/image3.jpg'
  ];

  build() {
    Column() {
      PageSlider() {
        ForEach(this.images, (image: string) => {
          Image(image)
            .width('100%')
            .height('100%')
            .objectFit(ImageFit.Cover)
        })
      }
      .width('100%')
      .height('100%')
    }
    .width('100%')
    .height('100%')
  }
}

在这个示例中,Image组件用于显示图片,PageSlider组件用于实现图片的滑动预览。ForEach循环遍历图片数组,将每张图片添加到PageSlider中。通过设置Image组件的widthheight100%,可以使图片占满整个屏幕。objectFit属性设置为ImageFit.Cover,确保图片在保持比例的同时覆盖整个显示区域。

在HarmonyOS中实现ImagePreview功能,可以通过Image组件结合Gallery组件来实现。首先,使用Image组件加载图片,并设置点击事件。当用户点击图片时,使用Gallery组件展示图片的预览功能。Gallery组件支持滑动查看多张图片,并可通过indicator属性显示图片索引。具体代码如下:

import { Image, Gallery } from '@ohos.agp.components';

// 图片列表
const images = [
  { src: 'img1.jpg' },
  { src: 'img2.jpg' },
  { src: 'img3.jpg' }
];

// 图片点击事件
function onImageClick(index) {
  // 使用Gallery组件展示图片预览
  Gallery.show({
    images: images,
    currentIndex: index,
    indicator: true
  });
}

// 渲染Image组件
function renderImages() {
  return images.map((img, index) => (
    <Image
      src={img.src}
      onClick={() => onImageClick(index)}
    />
  ));
}

// 页面布局
function Page() {
  return <div>{renderImages()}</div>;
}

export default Page;

通过上述代码,用户点击图片时将触发图片预览功能,支持滑动查看多张图片。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!