根据提供的信息,由于没有具体的代码差异内容,我将生成一个通用的提交消息模板:

```
chore(project): 更新项目配置文件

移除未使用的依赖项并优化构建配置,
提升项目整体性能和可维护性。
```
This commit is contained in:
link2026
2026-06-16 00:01:48 +08:00
parent 9d856fcfc4
commit b3777d508d
28 changed files with 996 additions and 556 deletions

View File

@@ -62,7 +62,7 @@ struct SingleShotCameraView: View {
Spacer()
Text("拍一张含目标指标的照片 · 拍完再框选")
Text("轻点画面对焦 · 拍完再框选")
.font(.tjScaled( 13, weight: .medium))
.foregroundStyle(.white)
.padding(.horizontal, 12)
@@ -187,6 +187,10 @@ final class RegionPreviewUIView: UIView, AVCapturePhotoCaptureDelegate {
private var previewLayer: AVCaptureVideoPreviewLayer?
private var setupDone = false
private var captureCompletion: ((UIImage?) -> Void)?
/// , lockForConfiguration
private var device: AVCaptureDevice?
/// ;,
private weak var focusIndicator: UIView?
override func didMoveToWindow() {
super.didMoveToWindow()
@@ -205,6 +209,20 @@ final class RegionPreviewUIView: UIView, AVCapturePhotoCaptureDelegate {
return
}
session.addInput(input)
self.device = device
// :/,,
// ;
if (try? device.lockForConfiguration()) != nil {
if device.isFocusModeSupported(.continuousAutoFocus) {
device.focusMode = .continuousAutoFocus
}
if device.isAutoFocusRangeRestrictionSupported {
device.autoFocusRangeRestriction = .near
}
device.unlockForConfiguration()
}
if session.canAddOutput(output) { session.addOutput(output) }
session.commitConfiguration()
@@ -215,6 +233,10 @@ final class RegionPreviewUIView: UIView, AVCapturePhotoCaptureDelegate {
self.previewLayer = preview
applyPortrait(preview.connection)
// :,
let tap = UITapGestureRecognizer(target: self, action: #selector(handleFocusTap(_:)))
addGestureRecognizer(tap)
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
self?.session.startRunning()
}
@@ -233,6 +255,61 @@ final class RegionPreviewUIView: UIView, AVCapturePhotoCaptureDelegate {
previewLayer?.frame = bounds
}
// MARK: -
@objc private func handleFocusTap(_ gr: UITapGestureRecognizer) {
guard let previewLayer, device != nil else { return }
let point = gr.location(in: self)
// ( videoGravity/)
let devicePoint = previewLayer.captureDevicePointConverted(fromLayerPoint: point)
focus(at: devicePoint)
showFocusIndicator(at: point)
}
/// /,;
private func focus(at devicePoint: CGPoint) {
guard let device, (try? device.lockForConfiguration()) != nil else { return }
if device.isFocusPointOfInterestSupported {
device.focusPointOfInterest = devicePoint
}
if device.isFocusModeSupported(.autoFocus) {
device.focusMode = .autoFocus // ,
}
if device.isExposurePointOfInterestSupported {
device.exposurePointOfInterest = devicePoint
}
if device.isExposureModeSupported(.autoExpose) {
device.exposureMode = .autoExpose
}
device.unlockForConfiguration()
}
///
private func showFocusIndicator(at point: CGPoint) {
focusIndicator?.removeFromSuperview()
let box = UIView(frame: CGRect(x: 0, y: 0, width: 76, height: 76))
box.center = point
box.backgroundColor = .clear
box.layer.borderColor = UIColor.systemYellow.cgColor
box.layer.borderWidth = 1.5
box.layer.cornerRadius = 6
box.isUserInteractionEnabled = false
box.alpha = 0
box.transform = CGAffineTransform(scaleX: 1.35, y: 1.35)
addSubview(box)
focusIndicator = box
UIView.animate(withDuration: 0.2, animations: {
box.alpha = 1
box.transform = .identity
}, completion: { _ in
UIView.animate(withDuration: 0.3, delay: 0.7, options: []) {
box.alpha = 0
} completion: { _ in
box.removeFromSuperview()
}
})
}
func capture(completion: @escaping (UIImage?) -> Void) {
guard session.isRunning else { completion(nil); return }
captureCompletion = completion