Explorar el Código

拍照与选择相册优化

wangcy hace 4 meses
padre
commit
a9ec00d5b6

+ 2 - 0
commons/basic/Index.ets

@@ -46,6 +46,8 @@ export * from "./src/main/ets/utils/YTBreakPoint"
 
 export { BasicType } from './src/main/ets/models/index'
 
+export * from '@mumu/crop'
+
 export * from './src/main/ets/models'
 
 

+ 3 - 2
commons/basic/oh-package.json5

@@ -10,9 +10,10 @@
     "@ohos/axios": "^2.2.4",
     "@abner/log": "^1.0.5",
     "@ibestservices/ibest-ui": "2.0.6",
-    "@tencent/wechat_open_sdk": "^1.0.0"
+    "@tencent/wechat_open_sdk": "^1.0.0",
+    "lunar": "^1.0.0",
+    "@mumu/crop": "^1.0.3"
   },
   "devDependencies": {},
   "dynamicDependencies": {},
-
 }

+ 5 - 0
commons/basic/src/main/ets/models/index.ets

@@ -47,6 +47,11 @@ export interface getCount {
 
 }
 
+export interface DelPhotoParam {
+  src: string,
+  type: 'bill' | 'header' | 'image'
+}
+
 /**
  * @description 结果回调函数的类型别名
  * @param res 结果输出

+ 10 - 0
commons/basic/src/main/ets/utils/YTRouter.ets

@@ -1,3 +1,5 @@
+import { DelPhotoParam } from '../models'
+
 class YTRouter extends NavPathStack {
   router2SettingPage() {
     yTRouter.pushPathByName('SettingPage', '')
@@ -37,6 +39,14 @@ class YTRouter extends NavPathStack {
     yTRouter.pushPathByName('LoginPage', '')
   }
 
+  router2DelPhotoPage(param: DelPhotoParam) {
+    yTRouter.pushPathByName('DelPhotoPage', param)
+  }
+
+  getDelPhotoParam() {
+    return yTRouter.getParamByName('DelPhotoPage').pop() as DelPhotoParam
+  }
+
   routerBack() {
     yTRouter.pop()
   }

+ 239 - 0
features/user/src/main/ets/pages/DelPhotoPage.ets

@@ -0,0 +1,239 @@
+import { CropController, CropView, IBestToast, YtAvoid, YTLog, yTRequest, yTRouter } from 'basic'
+import { fileIo } from '@kit.CoreFileKit'
+import { util } from '@kit.ArkTS'
+import { emitter } from '@kit.BasicServicesKit'
+
+@Builder
+function delPhotoPageBuilder() {
+  NavDestination() {
+    DelPhotoPage()
+  }
+  .hideTitleBar(true)
+}
+
+@Component
+struct DelPhotoPage {
+  @StorageProp(YtAvoid.safeBottomKey) private safeBottom: number = 0
+  @State private selectPhoto: string = ''
+  @State private frameWidth: number = 220
+  @State private frameHeight: number = 220
+  @State private startWidth: number = 220
+  @State private startHeight: number = 220
+  private declare type: 'bill' | 'header' | 'image'
+  private controller: CropController = new CropController()
+  private declare context: Context
+
+  aboutToAppear(): void {
+    this.selectPhoto = yTRouter.getDelPhotoParam().src
+    this.type = yTRouter.getDelPhotoParam().type
+    const tempContext = this.getUIContext().getHostContext()
+    if (tempContext === undefined) {
+      //抛出异常
+      throw new Error('DelPhotoPage context is null')
+    } else {
+      this.context = tempContext
+    }
+
+    YtAvoid.setStatusBarContentColor('#FFFFFF', this.context)
+  }
+
+  aboutToDisappear(): void {
+    YtAvoid.setStatusBarContentColor('#000000', this.context)
+  }
+
+  build() {
+    Column() {
+      Stack({ alignContent: Alignment.Center }) {
+        CropView({
+          src: this.selectPhoto,
+          controller: this.controller, // 控制器必须设置
+          maskColor: '#4D000000',
+          frameWidth: this.frameWidth,
+          frameHeight: this.frameHeight
+        })
+          .width("100%")
+          .layoutWeight(1)
+          .backgroundColor(Color.Black)
+        Column() {
+          Row() {
+            Text()
+              .height(30)
+              .aspectRatio(1)
+              .border({ width: { left: 8, top: 8 }, color: Color.White })
+              .offset({ x: -8, y: -8 })
+              .borderRadius({ topLeft: 5 })
+              .gesture(
+                PanGesture({ distance: 1 })
+                  .onActionStart(() => {
+                    // 记录拖拽开始时的初始尺寸
+                    this.startWidth = this.frameWidth
+                    this.startHeight = this.frameHeight
+                  })
+                  .onActionUpdate(event => {
+                    // 基于初始尺寸计算新尺寸
+                    const newWidth = Math.max(220, this.startWidth - event.offsetX)
+                    const newHeight = Math.max(220, this.startHeight - event.offsetY)
+
+                    // 同时更新两个维度
+                    this.frameWidth = newWidth
+                    this.frameHeight = newHeight
+                  })
+              )
+
+            Text()
+              .height(30)
+              .aspectRatio(1)
+              .border({ width: { right: 8, top: 8 }, color: Color.White })
+              .offset({ x: 8, y: -8 })
+              .borderRadius({ topRight: 5 })
+              .gesture(
+                PanGesture({ distance: 1 })
+                  .onActionStart(() => {
+                    // 记录拖拽开始时的初始尺寸
+                    this.startWidth = this.frameWidth
+                    this.startHeight = this.frameHeight
+                  })
+                  .onActionUpdate(event => {
+                    // 基于初始尺寸计算新尺寸
+                    const newWidth = Math.max(220, this.startWidth + event.offsetX)
+                    const newHeight = Math.max(220, this.startHeight - event.offsetY)
+
+                    // 同时更新两个维度
+                    this.frameWidth = newWidth
+                    this.frameHeight = newHeight
+                  })
+              )
+          }
+          .width('100%')
+          .height(25)
+          .justifyContent(FlexAlign.SpaceBetween)
+          .borderRadius(8)
+
+
+          Row() {
+            Text()
+              .height(30)
+              .aspectRatio(1)
+              .border({ width: { left: 8, bottom: 8 }, color: Color.White })
+              .offset({ x: -8, y: 8 })
+              .borderRadius({ bottomLeft: 5 })
+              .gesture(
+                PanGesture({ distance: 1 })
+                  .onActionStart(() => {
+                    // 记录拖拽开始时的初始尺寸
+                    this.startWidth = this.frameWidth
+                    this.startHeight = this.frameHeight
+                  })
+                  .onActionUpdate(event => {
+                    // 基于初始尺寸计算新尺寸
+                    const newWidth = Math.max(220, this.startWidth - event.offsetX)
+                    const newHeight = Math.max(220, this.startHeight + event.offsetY)
+
+                    // 同时更新两个维度
+                    this.frameWidth = newWidth
+                    this.frameHeight = newHeight
+                  })
+              )
+
+            Text()
+              .height(30)
+              .aspectRatio(1)
+              .border({ width: { right: 8, bottom: 8 }, color: Color.White })
+              .borderRadius({ bottomRight: 5 })
+              .offset({ x: 8, y: 8 })
+              .gesture(
+                PanGesture({ distance: 1 })
+                  .onActionStart(() => {
+                    // 记录拖拽开始时的初始尺寸
+                    this.startWidth = this.frameWidth
+                    this.startHeight = this.frameHeight
+                  })
+                  .onActionUpdate(event => {
+                    // 基于初始尺寸计算新尺寸
+                    const newWidth = Math.max(220, this.startWidth + event.offsetX)
+                    const newHeight = Math.max(220, this.startHeight + event.offsetY)
+
+                    // 同时更新两个维度
+                    this.frameWidth = newWidth
+                    this.frameHeight = newHeight
+                  })
+              )
+          }
+          .width('100%')
+          .height(25)
+
+          .justifyContent(FlexAlign.SpaceBetween)
+        }
+        .width(this.frameWidth)
+        .height(this.frameHeight)
+        .justifyContent(FlexAlign.SpaceBetween)
+        .hitTestBehavior(HitTestMode.Transparent)
+
+      }
+      .layoutWeight(1)
+
+      Row() {
+        Image($r('app.media.back'))
+          .width(36)
+          .aspectRatio(1)
+          .onClick(() => {
+            yTRouter.routerBack()
+          })
+
+        Image($r('app.media.make_sure'))
+          .height(56)
+          .aspectRatio(1)
+          .onClick(() => {
+            //使用 controller 获取裁剪图片
+            this.controller.cropWithPath({ format: 'image/jpeg', quality: 100 })
+              .then(async (path) => {
+                // path 为裁剪后的文件路径
+                try {
+                  const photoName = util.generateRandomUUID()
+                  const photoType = '.jpeg'
+                  const fullpath = this.context.cacheDir + '/' + photoName + photoType
+                  const photo = fileIo.openSync(path)
+                  await fileIo.copyFile(photo.fd, fullpath)
+
+                  if (this.type == 'header') {
+                    IBestToast.showLoading({ message: '上传中...' })
+                    yTRequest.uploadHeadImg(this.getUIContext().getHostContext()!, fullpath, () => {
+                      yTRequest.refreshUserInfo(() => {
+                        IBestToast.hide()
+                        setTimeout(() => {
+                          IBestToast.show({ message: '头像修改成功', type: 'success' })
+                        }, 100)
+                      })
+                    })
+                    yTRouter.routerBack()
+                  }
+                  if (this.type == 'image') {
+                    IBestToast.showLoading({ message: '上传中...' })
+                    yTRequest.uploadFile(this.getUIContext().getHostContext()!, fullpath, (url) => {
+                      emitter.emit('upLoadEnd', { data: url })
+                      IBestToast.hide()
+                      yTRouter.routerBack()
+                    })
+                  }
+
+                } catch (e) {
+                  YTLog.error(e)
+                }
+              })
+          })
+
+        Image($r('app.media.rotate'))
+          .height(36)
+          .aspectRatio(1)
+          .onClick(() => {
+            this.controller.rotate()
+          })
+      }
+      .width('100%')
+      .height(84)
+      .justifyContent(FlexAlign.SpaceAround)
+    }
+
+    .padding({ bottom: this.safeBottom })
+  }
+}

+ 3 - 11
features/user/src/main/ets/pages/SettingPage.ets

@@ -53,7 +53,7 @@ struct SettingPage {
         try {
           const fullpath = await takePicture()
           this.showHeaderImgRevise = false
-          // yTRouter.router2DelPhotoPage({ src: fullpath, type: 'header' })
+          yTRouter.router2DelPhotoPage({ src: fullpath, type: 'header' })
         } catch (e) {
           YTLog.warn(e)
         }
@@ -62,17 +62,9 @@ struct SettingPage {
     {
       text: '从相册中选择',
       click: () => {
-        Upload.selectImage(getContext(), (fullpath) => {
+        Upload.selectImage(this.getUIContext().getHostContext()!, (fullPath) => {
           this.showHeaderImgRevise = false
-          IBestToast.showLoading({ message: '上传中...' })
-          yTRequest.uploadHeadImg(getContext(), fullpath, () => {
-            yTRequest.refreshUserInfo(() => {
-              IBestToast.hide()
-              setTimeout(() => {
-                IBestToast.show({ message: '头像修改成功' })
-              }, 100)
-            })
-          })
+          yTRouter.router2DelPhotoPage({ src: fullPath, type: 'image' })
         })
       }
     },

BIN
features/user/src/main/resources/base/media/back.png


BIN
features/user/src/main/resources/base/media/make_sure.png


BIN
features/user/src/main/resources/base/media/rotate.png