鸿蒙原生应用 ArkUI 实战:虚线人脸框 + 双按钮 —— 证件照拍摄页的取景引导架构

App 51「个人证件照制作」拍摄页(Func1Tab),主题色 #2D3436 深灰黑(charcoal),4 个 Tab 分别为首页(🪪)、拍摄(📷)、编辑(✂️)、我的(👤)。本篇基于 51-id-photo/entry/src/main/ets/pages/Func1Tab.ets(共 78 行)逐段拆解,附 4 张实机截图。

51 拍摄页首屏

一、整体结构:四区"Header + 相机 + 动作 + 贴士"布局

拍摄页是"品牌头部 + 相机预览 + 拍摄动作 + 拍摄指导"的四区布局——3 个 @Builder 块:

build() {
  Column() {
    this.Header()
    Scroll() {
      Column({ space: 16 }) {
        this.CameraCard()
        this.ActionRow()
        this.TipCard()
      }
      .width('100%')
      .padding({ left: D.pad, right: D.pad, top: 16, bottom: D.pad + this.safeBottom + 20 })
    }
    .layoutWeight(1).scrollBar(BarState.Off).align(Alignment.Top)
  }
  .width('100%').height('100%').backgroundColor(C.bg)
}

4 块结构:Header(单行标题)→ CameraCard(相机预览+虚线人脸框)→ ActionRow(拍摄/上传双按钮)→ TipCard(4 条拍摄规范)。拍摄页是"照片的来源端"——相机预览引导"怎么拍"、双按钮提供"拍摄 or 上传"两种来源、贴士卡给出拍摄规范。

二、Header:单行标题

Header() {
  Row() { Text('拍摄照片').fontSize(20).fontWeight(FontWeight.Bold).fontColor(C.text) }
  .width('100%').height(this.safeTop + 56).padding({ top: this.safeTop, left: D.pad, right: D.pad })
  .backgroundColor(C.card).alignItems(VerticalAlign.Bottom)
}

20 号加粗、safeTop + 56 高度、白底底部对齐——系列二级页统一范式。"拍摄照片"与首页"证件照制作"(选规格)、编辑页"编辑照片"(修照片)形成"选 → 拍 → 编"流水线。

三、CameraCard:相机预览卡(虚线人脸框)

CameraCard() {
  Stack({ alignContent: Alignment.Center }) {
    Column().width('100%').height(300).backgroundColor('#2D3436').borderRadius(D.rLg)
    Column({ space: 12 }) {
      Text('👤').fontSize(80).opacity(0.5)
      Text('请将面部置于框内').fontSize(13).fontColor('#FFFFFF').opacity(0.8)
    }
    Column()
      .width(140).height(180)
      .border({ width: 2, color: '#FFFFFF', style: BorderStyle.Dashed }).borderRadius(8)
  }
  .width('100%')
}

逐点拆解:

  1. Stack 三层叠加:底层深灰底(#2D3436 300 高圆角 20)→ 中层人像引导(👤 80 号 50% 透明 + "请将面部置于框内"白字 80%)→ 顶层虚线框(140×180 白色虚线)——相机取景的视觉层次(背景/内容/取景框)。
  2. 虚线人脸框:BorderStyle.Dashed + 白 2 宽 + 圆角 8——140×180 对应证件照的"头身比"(头占画面约 70%),虚线"待填充"语义(把脸放入虚线框),与系列"虚线 = 待填充"(App 44 上传条、App 49 添加)语义一致。
  3. 半透明人像占位:opacity(0.5) ——👤 80 号半透明是"示意图"(不是真照片,是"这样拍"的示例),与虚线框共同构成拍摄示意。
  4. 深灰底的双重语义:#2D3436 既模拟相机取景画面(证件照深色背景标准)又是主题色——拍摄页的深灰与全 App 主题统一。

四、ActionRow:拍摄/相册双按钮

ActionRow() {
  Row({ space: 12 }) {
    Button('📷 拍摄').fontSize(15).fontColor('#FFFFFF').backgroundColor(C.primary)
      .layoutWeight(1).height(48).borderRadius(D.rMd)
      .onClick(() => { promptAction.showToast({ message: '拍摄照片' }); })
    Button('🖼️ 相册上传').fontSize(15).fontColor(C.primary).backgroundColor(C.primarySoft)
      .layoutWeight(1).height(48).borderRadius(D.rMd)
      .onClick(() => { promptAction.showToast({ message: '从相册选择' }); })
  }.width('100%')
}

逐点拆解:

  1. 双按钮等分:两个 layoutWeight(1) 各占一半,48 高圆角 14——拍摄/上传两种照片来源。
  2. 主次视觉:📷 拍摄 C.primary 深灰底白字(主动作)+ 🖼️ 相册上传 C.primarySoft 浅底深字(次动作)——视觉权重区分(拍摄优先)。
  3. 点击分支:拍摄 → "拍摄照片" Toast、上传 → "从相册选择" Toast——产品化后拍摄调 @ohos.multimedia.camera、上传调 PhotoViewPicker。

51 拍摄页拍摄 Toast

五、TipCard:拍摄小贴士(规范清单)

private tips: string[] = ['正对镜头,表情自然', '光线充足,避免阴影', '不戴帽子和有色眼镜', '穿深色上衣效果更佳'];
TipCard() {
  Column({ space: 12 }) {
    Text('💡 拍摄小贴士').fontSize(14).fontWeight(FontWeight.Bold).fontColor(C.text).width('100%')
    ForEach(this.tips, (t: string, idx: number) => {
      Row({ space: 8 }) {
        Text('✓').fontSize(13).fontColor(C.ok)
        Text(t).fontSize(13).fontColor(C.textSub).layoutWeight(1)
      }.width('100%')
    }, (t: string) => t)
  }
  .width('100%').padding(16).backgroundColor(C.card).borderRadius(D.rLg).border({ width: 1, color: C.stroke })
}

逐点拆解:

  1. 4 条硬性规范:正对镜头/光线充足/不戴帽子有色眼镜/穿深色上衣——覆盖姿态/光线/遮挡/着装,是证件照合规的检查清单。
  2. ✓ 绿色勾选:C.ok(#2BB673)绿色 + 13 号贴士文字——✓ 是"标准动作"的符号(每条都是"应该这样做"的规范)。
  3. "穿深色上衣"与主题呼应:贴士的"深色上衣"与主题色 #2D3436 深灰呼应——证件照着装建议与视觉主题统一。
  4. ForEach key:(t: string) => t ——贴士文字天然唯一。

51 拍摄页相册上传 Toast

六、系列横向对比:拍摄/引导类页面的三种形态

引导页代表 App引导方式核心元素虚线语义
拍摄引导App 51 拍摄页虚线人脸框 + 贴士140×180 取景框人脸位置
上传引导App 44 相册页虚线上传条添加入口待添加
制作引导App 43 明信片实时预览预览联动无虚线

差异点:本页虚线框是"位置引导"(放哪里),最接近真实相机的取景框;App 44 虚线是"添加引导"(点这里添加);App 43 是"预览引导"(看效果)。三类引导语义分明。

七、开发者视角:调试与验证技巧

    Column().width('100%').height(300).backgroundColor('#2D3436').borderRadius(D.rLg)
  1. 虚线框对齐:140×180 虚线框在 300 高深灰底上居中(Stack alignContent Center)——验证虚线框与人像 👤 水平垂直居中重叠。
  2. 双按钮分支:两个独立 onClick——验证"拍摄照片"与"从相册选择"两路径正确触发;主次按钮视觉(深灰 vs 浅底)不混淆。
  3. 贴士渲染:4 条 ForEach ——验证 ✓ 绿色与文字垂直对齐;新增贴士(数组加项)自动渲染。
  4. 深灰底对比度:#2D3436 + 白虚线 + 白字——真机验证深底白字清晰;👤 80 号 50% 透明度在深灰上可辨但不抢戏。
  5. 产品化相机接入:Demo 静态取景——产品化后深灰底换 @ohos.multimedia.camera 预览流,虚线框叠加在画面上(人脸识别可加"对齐提示"),虚线框骨架不变。

51 拍摄页完整视图

八、演进方向

方向当前状态产品化演进
相机预览静态深灰底 + 👤 示意@ohos.multimedia.camera 实时预览流
人脸对齐静态虚线框人脸识别 + 框变绿提示对齐
拍摄按钮Toast"拍摄照片"调起相机拍摄 → 跳编辑页
上传按钮Toast"从相册选择"调 PhotoViewPicker 选照片 → 跳编辑页
贴士增强静态 4 条文字实时检测(光线不足/人脸偏移)动态提示

九、一句话总结

拍摄页以"相机预览卡 + 双按钮 + 贴士"完成了照片来源的引导。Stack 三层叠加(深灰底 + 半透明人像 + 140×180 白色虚线框)是取景引导的核心、layoutWeight(1) 双按钮主次分明、4 条 ✓ 拍摄规范是合格证件照的检查清单——78 行代码,一个"按规范拍好证件照"的拍摄页,也是相机引导类页面的标准参考。

项目源码开源:https://gitee.com/codenestFlow/HarmonyOSHub

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐