/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { CommonLazyDataSourceModel } from '../model/CommonLazyDataSourceModel';
import { windowSizeManager } from '../utils/Managers';
import { PicturePreviewImage } from './PicturePreviewImage';
/**
* 使用图片预览组件样例
*
* 核心组件:
* 一. PicturePreview
* 二. PicturePreviewImage
*
* 实现步骤:
* 一、PicturePreview
* - 1. 使用 List 来使用多图片的移动和展示
* - 2. 当图片处于边缘位置可以通过 ListScroller 来进行图片预览的位移
*
* 二、PicturePreviewImage
* - 1. 使用matrix实现图片的缩放
* - 2. 使用offset实现组件的偏移
* - 3. 提前计算图片属性以便对组件属性进行设置
* - 4. Image.objectFile使用Cover以便图片能够超出其父组件显示(而不撑大父组件)
*
* @param { Axis } [listDirection] - 图片预览的主轴方向, 默认水平滑动
* @param { string[] } imageList - 图片数据列表
*/
@Component
export struct PicturePreview {
// 滑动方向
@Prop listDirection: Axis = Axis.Vertical;
// 外部传入的图片数据
@Link @Watch('getListMaxLength') imageList: string[];
// 背景颜色
@State listBGColor: Color = Color.White;
// 图片懒加载数据源
@State lazyImageList: CommonLazyDataSourceModel<string> = new CommonLazyDataSourceModel();
// 当前视图下标
private listIndex: number = 0;
// 图片数量
private listMaxLength: number = 0;
// list 滑动控制器
private listScroll: ListScroller = new ListScroller();
// list间距
private listSpace: number = 10;
// list滑动动画时长
private listAnimationDuration: number = 500;
// 获取图片数量和设置懒加载图片数据
getListMaxLength() {
this.listMaxLength = this.imageList.length;
this.lazyImageList.clearAndPushAll(this.imageList)
}
// 改变偏移量
setListOffset = (offset: number, animationDuration: number = 0) => {
const WIN_SIZE = windowSizeManager.get();
let principalAxisSize = this.listDirection === Axis.Horizontal ? WIN_SIZE.width : WIN_SIZE.height
let principalAxisOffset = principalAxisSize * this.listIndex;
let space = this.listSpace * this.listIndex;
principalAxisOffset = principalAxisOffset + space;
let calculatedOffset = offset + principalAxisOffset;
this.listScroll.scrollTo({
yOffset: this.listDirection === Axis.Horizontal ? 0 : calculatedOffset,
xOffset: this.listDirection === Axis.Horizontal ? calculatedOffset : 0,
animation: {
duration: animationDuration
}
})
}
// 改变到具体页面
setListToIndex = (index: number) => {
const WIN_SIZE = windowSizeManager.get();
let nIndex = index;
if (nIndex < 0) {
nIndex = 0
} else if (nIndex >= this.listMaxLength) {
nIndex = this.listMaxLength - 1
}
this.listIndex = nIndex;
let principalAxisSize = this.listDirection === Axis.Horizontal ? WIN_SIZE.width : WIN_SIZE.height
let calculatedOffset = Math.abs(nIndex * principalAxisSize) + this.listSpace * nIndex;
this.listScroll.scrollTo({
yOffset: this.listDirection === Axis.Horizontal ? 0 : calculatedOffset,
xOffset: this.listDirection === Axis.Horizontal ? calculatedOffset : 0,
animation: {
duration: this.listAnimationDuration
}
})
}
/**
* 初始化数据源
*/
aboutToAppear(): void {
this.getListMaxLength()
}
build() {
NavDestination() {
List({ scroller: this.listScroll, space: this.listSpace }) {
LazyForEach(this.lazyImageList, (imageUrl: string, index: number) => {
ListItem() {
PicturePreviewImage({
imageUrl: imageUrl,
listDirection: this.listDirection,
setListOffset: this.setListOffset,
setListToIndex: this.setListToIndex,
imageIndex: index,
imageMaxLength: this.listMaxLength,
listBGColor: this.listBGColor
})
}
.width("100%")
})
}
.enableScrollInteraction(false) // PicturePreviewImage中根据自定义手势控制滑动,需要禁止List本身的滑动,否则会出现滑动冲突
.scrollSnapAlign(ScrollSnapAlign.START)
.width("100%")
.height("100%")
.cachedCount(1)
.listDirection(this.listDirection)
.scrollBar(BarState.Off)
.backgroundColor(this.listBGColor)
.onClick(() => {
this.listBGColor = this.listBGColor === Color.White ? Color.Black : Color.White;
})
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
// 注意:边框不可去除,这一步是为了防止鸿蒙定位Y轴上移,等待华为修复
.borderWidth(1)
.borderColor(Color.Transparent)
}
.hideTitleBar(true)
}
}