diff --git a/app/entry/src/main/ets/core/ImageCodec.ets b/app/entry/src/main/ets/core/ImageCodec.ets index 2c24653..f1e8848 100644 --- a/app/entry/src/main/ets/core/ImageCodec.ets +++ b/app/entry/src/main/ets/core/ImageCodec.ets @@ -18,6 +18,7 @@ import { image } from '@kit.ImageKit' import { util } from '@kit.ArkTS' +import { BusinessError } from '@kit.BasicServicesKit' import { photoAccessHelper } from '@kit.MediaLibraryKit' import { cameraPicker } from '@kit.CameraKit' import { camera } from '@kit.CameraKit' @@ -70,6 +71,12 @@ export class ImageCodec { ) } + /** 用户取消判定:多数路径取消返回空数组,但预览态/部分 ROM 会 reject 13900042。 */ + private static isUserCancel(e: Object): boolean { + const code: number | undefined = (e as BusinessError).code + return code === 13900042 + } + /** 相册选 1 张。用户取消返回 undefined。 */ static async pickFromGallery(): Promise { const picker = new photoAccessHelper.PhotoViewPicker() @@ -90,6 +97,9 @@ export class ImageCodec { return { uri: res.photoUris[0], width: 0, height: 0 } } catch (e) { hilog.error(IMG_DOMAIN, IMG_TAG, 'gallery: pick failed: %{public}s', String(e)) + if (ImageCodec.isUserCancel(e)) { + return undefined // 取消不报错(页面保持原状,不弹「读取照片失败」) + } throw e as Error } } @@ -109,6 +119,9 @@ export class ImageCodec { return { uri: res.resultUri, width: 0, height: 0 } } catch (e) { hilog.error(IMG_DOMAIN, IMG_TAG, 'camera: pick failed: %{public}s', String(e)) + if (ImageCodec.isUserCancel(e)) { + return undefined // 取消不报错 + } throw e as Error } } diff --git a/app/entry/src/main/ets/pages/HairColorPage.ets b/app/entry/src/main/ets/pages/HairColorPage.ets index c812b3c..c097687 100644 --- a/app/entry/src/main/ets/pages/HairColorPage.ets +++ b/app/entry/src/main/ets/pages/HairColorPage.ets @@ -303,7 +303,8 @@ struct HairColorPage { .backgroundColor(COLOR_IMAGE_BG) .alignSelf(ItemAlign.Start) - // 图片区(单区域):无照片=上传入口;生成中=loading;按页签显示原图/效果图 + // 图片区(单区域,定高 320):无照片=上传入口;生成中=loading;按页签显示原图/效果图。 + // 注意 Stack 必须显式定高:内部额度胶囊 Row 用 height(100%),不定高会被 Scroll 视口撑飞 Stack({ alignContent: Alignment.BottomStart }) { if (this.photoUri.length === 0) { Column({ space: 6 }) { @@ -321,11 +322,9 @@ struct HairColorPage { .width('100%').height(320).justifyContent(FlexAlign.Center) .borderRadius(12).backgroundColor(COLOR_IMAGE_BG) } else if (this.imageTab === 1 && this.resultPm !== undefined) { - // 顶部对齐裁切:容器定高 clip,图片只定宽按原比缩放,头顶/发型不被居中裁掉 - Column() { - Image(this.resultPm).width('100%').objectFit(ImageFit.Cover) - } - .width('100%').height(320).clip(true).borderRadius(12).backgroundColor(COLOR_IMAGE_BG) + // Cover 居中裁切:人脸通常在画面中央,头顶/下巴各让一点比只切下巴安全 + Image(this.resultPm) + .width('100%').height(320).objectFit(ImageFit.Cover).borderRadius(12) Text('效果图') .fontSize(11).fontColor(Color.White) .padding({ left: 10, right: 10, top: 4, bottom: 4 }) @@ -333,11 +332,8 @@ struct HairColorPage { .backgroundColor(COLOR_BADGE_BG) .margin(8) } else { - // 顶部对齐裁切:同上 - Column() { - Image(this.photoUri).width('100%').objectFit(ImageFit.Cover) - } - .width('100%').height(320).clip(true).borderRadius(12).backgroundColor(COLOR_IMAGE_BG) + Image(this.photoUri) + .width('100%').height(320).objectFit(ImageFit.Cover).borderRadius(12) Text('原图') .fontSize(11).fontColor(Color.White) .padding({ left: 10, right: 10, top: 4, bottom: 4 }) @@ -363,6 +359,7 @@ struct HairColorPage { } } .width('100%') + .height(320) // 入口文字链:相册/拍照 + 保存(有结果才可点) Row({ space: 16 }) { diff --git a/app/entry/src/main/ets/pages/HairDesignPage.ets b/app/entry/src/main/ets/pages/HairDesignPage.ets index 9492ece..8deda87 100644 --- a/app/entry/src/main/ets/pages/HairDesignPage.ets +++ b/app/entry/src/main/ets/pages/HairDesignPage.ets @@ -340,7 +340,8 @@ struct HairDesignPage { .backgroundColor(COLOR_IMAGE_BG) .alignSelf(ItemAlign.Start) - // 图片区(单区域):无照片=上传入口;生成中=loading;按页签显示原图/效果图 + // 图片区(单区域,定高 320):无照片=上传入口;生成中=loading;按页签显示原图/效果图。 + // 注意 Stack 必须显式定高:内部额度胶囊 Row 用 height(100%),不定高会被 Scroll 视口撑飞 Stack({ alignContent: Alignment.BottomStart }) { if (this.photoUri.length === 0) { Column({ space: 6 }) { @@ -358,11 +359,9 @@ struct HairDesignPage { .width('100%').height(320).justifyContent(FlexAlign.Center) .borderRadius(12).backgroundColor(COLOR_IMAGE_BG) } else if (this.imageTab === 1 && this.resultPm !== undefined) { - // 顶部对齐裁切:容器定高 clip,图片只定宽按原比缩放,头顶/发型不被居中裁掉 - Column() { - Image(this.resultPm).width('100%').objectFit(ImageFit.Cover) - } - .width('100%').height(320).clip(true).borderRadius(12).backgroundColor(COLOR_IMAGE_BG) + // Cover 居中裁切:人脸通常在画面中央,头顶/下巴各让一点比只切下巴安全 + Image(this.resultPm) + .width('100%').height(320).objectFit(ImageFit.Cover).borderRadius(12) Text('效果图') .fontSize(11).fontColor(Color.White) .padding({ left: 10, right: 10, top: 4, bottom: 4 }) @@ -370,11 +369,8 @@ struct HairDesignPage { .backgroundColor(COLOR_BADGE_BG) .margin(8) } else { - // 顶部对齐裁切:同上 - Column() { - Image(this.photoUri).width('100%').objectFit(ImageFit.Cover) - } - .width('100%').height(320).clip(true).borderRadius(12).backgroundColor(COLOR_IMAGE_BG) + Image(this.photoUri) + .width('100%').height(320).objectFit(ImageFit.Cover).borderRadius(12) Text('原图') .fontSize(11).fontColor(Color.White) .padding({ left: 10, right: 10, top: 4, bottom: 4 }) @@ -400,6 +396,7 @@ struct HairDesignPage { } } .width('100%') + .height(320) // 入口文字链:相册/拍照 + 保存(有结果才可点) Row({ space: 16 }) {