实现一个HarmonyOS 鸿蒙Next ImagePreview的功能
实现一个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'
})
}
}
实现思路
- window.createWindow 可以创建一个子窗口
- 使用子窗口 loadContentByName 加载一个命名路由页面
- loadContentByName 加载页面中给页面注入一个 LocalStorage
- 页面读取 LocalStorage 渲染下图片预览
- 点击关闭按钮销毁子窗口
具体代码
组件封装
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()
}
}
}
使用
- 在 ability 的生命周期里初始化 context
import { ImagePreview } from 'JImagePreview'
export default class EntryAbility extends UIAbility {
onCreate() {
// 初始化 context
ImagePreview.initContext(this.context)
}
}
- 使用
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
补充个效果

更多关于实现一个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
组件的width
和height
为100%
,可以使图片占满整个屏幕。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;
通过上述代码,用户点击图片时将触发图片预览功能,支持滑动查看多张图片。