1、HarmonyOS 折叠屏手机如何判断当前是展开还是折叠状态?
请参考API获取当前可折叠设备的折叠状态:developer.huawei.com/consumer/cn…
FoldStatus 当前可折叠设备的折叠状态枚举。
| 名称 | 值 | 说明 |
|---|---|---|
| FOLD_STATUS_UNKNOWN | 0 | 表示设备当前折叠状态未知。 |
| FOLD_STATUS_EXPANDED | 1 | 表示设备当前折叠状态为完全展开。 |
| FOLD_STATUS_FOLDED | 2 | 表示设备当前折叠状态为折叠。 |
| FOLD_STATUS_HALF_FOLDED | 3 | 表示设备当前折叠状态为半折叠。半折叠指完全展开和折叠之间的状态。 |
2、HarmonyOS H5页面选择图片可以从onShowFileSelector 监听到,但是H5页面选择视频的时候,从onShowFileSelector监听不到。请问是从别的方法中监听吗?
H5页面选择图片可以从onShowFileSelector 监听到,但是H5页面选择视频的时候,从onShowFileSelector监听不到。请问是从别的方法中监听吗?
H5页面选择视频的时候onShowFileSelector可以监听,参考如下文档和例子。
文档:developer.huawei.com/consumer/cn…
onShowFileSelector(callback: Callback<OnShowFileSelectorEvent, boolean>) 调用此函数以处理具有“文件”输入类型的HTML表单。如果不调用此函数或返回false,Web组件会提供默认的“选择文件”处理界面。如果返回true,应用可以自定义“选择文件”的响应行为。
例子:
@Entry
@Component
export struct WebComponent {
controller: webview.WebviewController = new webview.WebviewController()
build() {
Column() {
Web({ src: $rawfile('index.html'), controller: this.controller })
.onShowFileSelector((event) => {
if (event) {
let photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
let photoPicker = new photoAccessHelper.PhotoViewPicker();
// 过滤选择媒体文件类型为IMAGE
photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_VIDEO_TYPE;
// 设置最大选择数量
photoSelectOptions.maxSelectNumber = 5;
// let chooseFile: picker.PhotoSelectResult = await photoPicker.select(photoSelectOptions);
photoPicker.select(photoSelectOptions).then((res)=>{
console.log('asd===',JSON.stringify(res.photoUris))
}).catch((err:Error)=>{
})
console.log('res ===',JSON.stringify(event))
}
return true;
})
}
}
}
3、HarmonyOS 点击图片放大缩小?
请问下有没有图片大图浏览的组件,可双击点击放大缩小。
当前并无相关组件可用于查看大图,具体实现方式可参考图库查看大图、左右切换浏览图片源码:gitee.com/openharmony…
或者参考如下代码:
1.Page页面:
// xxx.ets
import router from '@ohos.router'
@Entry
@Component
struct SharedTransitionExample {
@State active: boolean = false
@State imageNames: Resource[] = [$r('app.media.image1'), $r('app.media.image2'), $r('app.media.image3')]
@StorageLink('currentIndex') currentIndex: number = 0
build() {
Row() {
ForEach(this.imageNames, (res: Resource, index: number) => {
Column() {
Image(res)
.width('100%')
.height('100%')
.objectFit(ImageFit.Contain) // 在组件上绑定缩放比例,可以通过修改缩放比例来实现组件的缩小或者放大
}
.width(100)
.height(100)
.clip(true)
.sharedTransition('sharedImage' + res.id, {
duration: 200,
curve: Curve.Linear,
zIndex: this.currentIndex === index ? 10 : -10
})
.onClick(() => {
this.currentIndex = index
router.pushUrl({ url: 'pages/Index', params: {
data: this.imageNames,
} })
})
})
}.width('100%')
.height('100%')
}
pageTransition() {
PageTransitionEnter({ duration: 0, curve: Curve.Linear })
.onEnter((type?: RouteType, progress?: number) => {
}) // 进场过程中会逐帧触发onEnter回调,入参为动效的归一化进度(0% -- 100%)
PageTransitionExit({ duration: 0, curve: Curve.Ease })
.onExit((type?: RouteType, progress?: number) => {
}) // 退场过程中会逐帧触发onExit回调,入参为动效的归一化进度(0% -- 100%)
}
}
//2.Index页面
import window from '@ohos.window';
import router from '@ohos.router';
interface Data {
data: Resource[];
}
enum Direction {
None,
Left,
Right,
}
@Entry
@Component
struct Index {
private swiperController: SwiperController = new SwiperController();
@State imageNames: Resource[] = []
@StorageLink('currentIndex') currentIndex: number = 0
@State screenWidth: number = 0;
@State op: number = 0
aboutToAppear() {
const data = (router.getParams() as Data)
this.imageNames = data.data
window.getLastWindow(getContext(this)).then(currentWindow => {
let property = currentWindow.getWindowProperties();
this.screenWidth = property.windowRect.width;
})
}
build() {
Stack({ alignContent: Alignment.Center }) {
Swiper(this.swiperController) {
ForEach(this.imageNames, (name: Resource, index: number) => {
Column() {
ImageComponent({
image: name,
viewWidth: this.screenWidth,
isCurrent: this.currentIndex === index,
onNeedGoNext: (dire: Direction) => {
if (dire === Direction.Right) {
this.swiperController.showNext()
} else if (dire === Direction.Left) {
this.swiperController.showPrevious()
}
}
}).zIndex(index == this.currentIndex ? 2 : 1)
}.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
})
}
.index(this.currentIndex)
.indicator(false)
.disableSwipe(true)
.itemSpace(10)
.onChange((index: number) => {
this.currentIndex = index
})
}.width('100%').height('100%')
.backgroundColor(`rgba(0,0,0,${this.op})`)
}
pageTransition() {
PageTransitionEnter({ duration: 200, curve: Curve.Linear })
.onEnter((type?: RouteType, progress?: number) => {
if (progress) {
this.op = progress
}
}) // 进场过程中会逐帧触发onEnter回调,入参为动效的归一化进度(0% -- 100
@Component
struct ImageComponent {
private image: Resource = $r('app.media.icon')
private preGeometryScale: number = 1
@State geometryScale: number = 1
private preOffsetX: number = 0
private preOffsetY: number = 0
@State geometryOffsetX: number = 0
@State geometryOffsetY: number = 0
@State imageWidth: number = 0
@State imageHeight: number = 0
@Prop viewWidth: number = 0
@Prop isCurrent: boolean = false
private dire: Direction = Direction.None
private goNext: boolean = true
private pinching: boolean = false
private onNeedGoNext: (dire: Direction) => void = () => {
}
reset(): Promise<void> | undefined {
this.preGeometryScale = 1
this.preOffsetX = 0
this.preOffsetY = 0
this.dire = Direction.None
this.goNext = true
if (this.geometryScale === 1) return
return new Promise<void>(res => {
animateTo({ duration: 200, onFinish: res }, () => {
this.geometryScale = 1
this.geometryOffsetX = 0
this.geometryOffsetY = 0
})
})
}
build() {
Column() {
Image(this.image)
.onComplete((e) => {
this.imageWidth = (e?.width || 0)
this.imageHeight = (e?.height || 0)
})
.objectFit(ImageFit.Cover)
.width(this.imageWidth + 'px')
.height(this.imageHeight + 'px')
.scale({
x: this.geometryScale,
y: this.geometryScale
})
.offset({
x: this.geometryOffsetX,
y: this.geometryOffsetY
})
.focusable(true)
.objectFit(ImageFit.Cover)
.autoResize(false)
.sharedTransition('sharedImage' + this.image.id, {
duration: 200,
curve: Curve.Linear,
zIndex: this.isCurrent ? 10 : -10
})
}
.clip(true)
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.hitTestBehavior(HitTestMode.Default)
.parallelGesture( // 在组件上绑定二指触发的捏合手势
GestureGroup(GestureMode.Parallel,
PinchGesture({ fingers: 2 })
.onActionStart((event: GestureEvent) => {
this.pinching = true
this.goNext = false
})// 当捏合手势触发时,可以通过回调函数获取缩放比例,从而修改组件的缩放比例
.onActionUpdate((event: GestureEvent) => {
const s = this.preGeometryScale * event.scale;
this.geometryScale = Math.max(0.6, Math.min(2, s))
})
.onActionEnd(async () => {
this.preGeometryScale = this.geometryScale
if (this.preGeometryScale < 1) {
await this.reset()
}
this.pinching = false
}),
PanGesture()
.onActionStart((event?: GestureEvent) => {
})
.onActionUpdate((event?: GestureEvent) => {
let offsetX = this.preOffsetX + (event?.offsetX || 0)
let offsetY = this.preOffsetY + (event?.offsetY || 0)
if (((this.imageWidth * this.geometryScale - this.viewWidth) / 2 - Math.abs(vp2px(offsetX))) <= 0) {
if (!this.pinching) {
this.dire = offsetX < 0 ? Direction.Right : Direction.Left
}
return;
}
this.goNext = false
this.geometryOffsetX = offsetX
this.geometryOffsetY = offsetY
})
.onActionEnd((event?: GestureEvent) => {
if ((this.dire !== Direction.None)) {
if (this.goNext) {
this.onNeedGoNext(this.dire)
this.reset()
}
this.goNext = true
}
this.preOffsetX = this.geometryOffsetX
this.preOffsetY = this.geometryOffsetY
}),
)
)
}
}
4、HarmonyOS 组件刷新问题?
struct MyFoldPage {
@State filePaths: FolderModel[] = []
build() {
Column(){
Grid() {
ForEach(this.filePaths, (item: FolderModel, index: number) => {
GridItem() {
this.ItemBuilder(index)
}
}, (item: FolderModel) => item.fileName)
}
}
}
}
export class FolderModel {
filePath: string = ''
fileName: string = ''
isScreenshot: boolean = true
thumbnailPath?: string = '' //当文件是视频的时候,抓视频的缩略图pixelMap
isSelect?: boolean = false
}
现在有个问题是修改了数组内部item类里面isSelect的值,整个列表不会自动刷新,必须要新new一个item并重新赋值给filepaths才能更新,有没有比较好的实现方式
请使用@Observed装饰器和@ObjectLink装饰器实现该场景,具体使用方法请参考文档。文档链接:developer.huawei.com/consumer/cn…
5、HarmonyOS 自定义组件,数据更新时,界面无法重新渲染?
@Component
export struct CardView {
@State title: string | undefined = undefined
@State moreText: string = '更多'
@Builder
tempBuilder() {
};
@BuilderParam contentBuilder: () => void = this.tempBuilder
build() {
this.contentBuilder()
}
}
//组件被调用
@Component
export struct NoticeCardView {
@State noticeList: Notice[] = []
aboutToAppear(): void {
new NoticeRepository().getNoticeList().then((result) => {
this.noticeList = result
})
}
@Builder
ContentBuilder() {
ForEach(this.noticeList, (notice: Notice) => {
Row() {
Image($r('app.media.wb_ic_notice_tip')).height(11).width(9)
Text(notice.title)
.margin({ left: 11 })
.fontColor($r('app.color.cm_text_primary'))
.fontSize('14fp')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}.padding(8)
})
}
build() {
CardView({
title: '',
contentBuilder: this.ContentBuilder
})
}
}
自定义组件noticeList更新时,无法触发界面更新,无法渲染出列表展示
参考以下代码:
@Component
struct CardView {
@Prop header: string = '';
@Builder tempBuilder(){}
@BuilderParam contentBuilder: () => void = this.tempBuilder
build() {
Column() {
this.contentBuilder()
}
}
}
@Entry
@Component
struct CustomContainerUser {
@State text: string = 'header';
@State list: string[] = []
aboutToAppear(): void {
this.list.push("1");
this.list.push("2");
this.list.push("3");
console.log('打印一下',this.list)
}
build() {
Column() {
Text(this.text)
CardView ({ header: this.text }) {
Column() {
this.ContentBuilder('testA', 'testB')
}.backgroundColor(Color.Yellow)
}
}
}
@Builder ContentBuilder(label1: string, label2: string) {
Column() {
Text('test')
ForEach(this.list, (text: string) => {
Text(text)
})
}
}
}