鸿蒙相机开发中篇:自定义 UI 与拍摄控制
------ 前后摄像头切换、点击对焦、曝光控制与动画动效
一、前言
上一篇《鸿蒙相机开发入门篇》中,我们完成了一个最小可用的相机应用,能实现预览与拍照。
但真正的相机 App 不只是能"拍",还要有流畅的交互体验,比如:
- 自定义取景框
- 切换前后摄像头
- 点击自动对焦
- 曝光补偿与预览动画
本篇将继续基于 @ohos.multimedia.camera
模块,带你逐步构建一个带交互控制与动效的相机 UI。
二、核心知识点回顾
功能 | 使用类 | 说明 |
---|---|---|
前后摄像头切换 | CameraManager.getSupportedCameras() |
返回多个可用摄像头,通常索引 0 是后置,1 是前置 |
对焦控制 | CameraInput.setFocusMode() / CameraInput.setFocusPoint() |
设置自动/手动对焦点 |
曝光补偿 | CameraInput.setExposureBias() |
调节亮度 |
动画动效 | ArkUI 动画系统 (.animation ) |
提供平滑的过渡和点击反馈 |
三、自定义取景框与 UI 布局
我们使用一个半透明取景框 + 工具栏布局:
typescript
// pages/CustomCameraPage.ets
import camera from '@ohos.multimedia.camera';
import { prompt } from '@kit.ArkUI';
@Entry
@Component
struct CustomCameraPage {
@State isFront: boolean = false;
@State focusX: number = 0;
@State focusY: number = 0;
controller: camera.CameraManager = camera.getCameraManager(globalThis.context);
session?: camera.Session;
cameraInput?: camera.CameraInput;
previewOutput?: camera.PreviewOutput;
photoOutput?: camera.PhotoOutput;
build() {
Stack() {
// 相机预览区域
XComponent({ id: 'cameraPreview', type: XComponentType.SURFACE })
.onLoad((context) => this.initCamera(context))
.width('100%')
.height('100%')
.onTouch((event) => this.handleFocus(event)) // 点击对焦
// 取景框遮罩
Rect()
.width('80%')
.height('60%')
.border({ width: 2, color: '#FFFFFF' })
.opacity(0.5)
.align(Alignment.Center)
// 对焦点动画
if (this.focusX !== 0) {
Image($r('app.media.focus_ring'))
.width(40)
.height(40)
.position({ x: this.focusX - 20, y: this.focusY - 20 })
.animation({ duration: 300, curve: Curve.EaseOut })
}
// 底部工具栏
Column({ space: 20 }) {
Button(this.isFront ? '切换后摄' : '切换前摄')
.onClick(() => this.switchCamera())
.width(160).height(50)
.backgroundColor('#444').fontColor('#fff').borderRadius(25)
Button('拍照')
.onClick(() => this.takePhoto())
.width(100).height(100)
.borderRadius(50)
.backgroundColor('#007DFF')
}
.align(Alignment.BottomCenter)
.padding(20)
}
}
四、前后摄像头切换逻辑
kotlin
async initCamera(context) {
const cameras = this.controller.getSupportedCameras();
const selected = cameras[this.isFront ? 1 : 0];
this.cameraInput = this.controller.createCameraInput(selected);
this.previewOutput = this.controller.createPreviewOutput(context);
this.photoOutput = this.controller.createPhotoOutput();
this.session = this.controller.createSession(camera.SessionType.SESSION_TYPE_NORMAL);
await this.session.beginConfig();
this.session.addInput(this.cameraInput);
this.session.addOutput(this.previewOutput);
this.session.addOutput(this.photoOutput);
await this.session.commitConfig();
await this.cameraInput.open();
this.previewOutput.start();
}
async switchCamera() {
this.isFront = !this.isFront;
await this.session?.stop();
await this.cameraInput?.close();
await this.initCamera(globalThis.context);
}
五、点击自动对焦
ini
handleFocus(event) {
const point = event.touches[0];
this.focusX = point.x;
this.focusY = point.y;
if (this.cameraInput) {
this.cameraInput.setFocusMode(camera.FocusMode.AUTO);
this.cameraInput.setFocusPoint({ x: point.x, y: point.y });
}
setTimeout(() => {
this.focusX = 0; // 动画结束隐藏
this.focusY = 0;
}, 800);
}
🔍 说明
setFocusMode()
可切换到自动或手动对焦。- 坐标点是基于 XComponent 的触摸事件。
- 通过短暂显示对焦圆环动画反馈用户操作。
六、增加曝光调节
scss
Slider({ value: 0, min: -1, max: 1, step: 0.1 })
.onChange((value) => {
if (this.cameraInput) {
this.cameraInput.setExposureBias(value);
}
})
.width('60%')
.align(Alignment.BottomCenter)
.margin({ bottom: 80 })
🌞 曝光值范围通常为 [-1, 1],可以根据光线场景动态调整。
七、小结与下一篇预告
到这里,我们已经实现了:
✅ 前后摄像头切换
✅ 点击自动对焦
✅ 曝光调节
✅ 自定义 UI 与对焦动效
下一篇(下篇:相机动效与性能优化)我们将继续探讨:
- 相机启动/恢复动画
- 快门和聚焦动效
- 在 Worker 线程中使用相机(性能优化)
- HDR、Vivid、高帧率预览