The following process calls the screen
import SwiftUI
internal struct ListView: View {
@State private var scanData: ScanData = ScanData()
var body: some View {
NavigationStack {
List {
ListItem(
title: "shoulder width",
description: "scan shoulder max width",
length: $scanData.shoulderWidth
)
.overlay {
NavigationLink(value: ScanType.shoulderWidth) {
EmptyView()
}
.opacity(0)
}
.listRowBackground(Color.white)
.listRowSeparator(.hidden)
ListItem(
title: "forearm width",
description: "scan forearm max width",
length: $scanData.forearmWidth
)
.overlay {
NavigationLink(value: ScanType.shoulderWidth) {
EmptyView()
}
.opacity(0)
}
.listRowBackground(Color.white)
.listRowSeparator(.hidden)
ListItem(
title: "knee thickness",
description: "scan knee thickness",
length: $scanData.kneeThicknessWidth
)
.overlay {
NavigationLink(value: ScanType.shoulderWidth) {
EmptyView()
}
.opacity(0)
}
.listRowBackground(Color.white)
.listRowSeparator(.hidden)
}
.listStyle(.plain)
.navigationDestination(for: ScanType.self) { type in
MeasureARView(
title: "scan for ",
bodyImageName: "PersonForearm",
startPointBackgroundImageName: "BackgroundForearm",
endPointBackgroundImageName: "BackgroundForearmEnd",
startPointExplainText: "Tap the start point. Move the cursor and tap the button at the point",
lastResult: nil,
mode: .width,
bindLength: type == .foreArm ? $scanData.forearmWidth :
type == .knee ? $scanData.kneeThicknessWidth :
type == .shoulderWidth ? $scanData.shoulderWidth : .constant(nil)
)
}
}
}
}
import ARKit
import AVFoundation
import SwiftUI
internal struct MeasureARView: View {
let synthesizer: AVSpeechSynthesizer = AVSpeechSynthesizer()
let title: String
let bodyImageName: String
let startPointBackgroundImageName: String
let endPointBackgroundImageName: String
let startPointExplainText: String
let lastResult: Double?
let mode: MeasurementMode
@Binding var bindLength: Double?
@State private var length: Double?
@State private var tapCount: Int = 0
@State private var currentIndex: Int = 0
@Environment(\.dismiss)
private var dismiss: DismissAction
init(
title: String,
bodyImageName: String,
startPointBackgroundImageName: String,
endPointBackgroundImageName: String,
startPointExplainText: String,
lastResult: Double?,
mode: MeasurementMode,
bindLength: Binding<Double?>
) {
self.title = title
self.bodyImageName = bodyImageName
self.startPointBackgroundImageName = startPointBackgroundImageName
self.endPointBackgroundImageName = endPointBackgroundImageName
self.startPointExplainText = startPointExplainText
self.lastResult = lastResult
self.mode = mode
self.currentIndex = mode.rawValue
self._bindLength = bindLength
}
var body: some View {
ZStack {
MeasureARViewContainer(
tapCount: $tapCount,
distance: $length,
currentIndex: $currentIndex
)
GeometryReader { geometry in
SegmentedPicker(
width: geometry.size.width,
contents: ["thickness", "width"],
selection: $currentIndex
)
Image(tapCount == 0 ? startPointBackgroundImageName : endPointBackgroundImageName)
.resizable()
.frame(width: geometry.size.width, height: geometry.size.height)
.accessibility(label: Text("imageIcon"))
.opacity(0.5)
}
Text("+")
.font(.largeTitle)
.foregroundStyle(.red)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
VStack {
Image(bodyImageName, label: Text(bodyImageName))
.resizable()
.frame(width: 30, height: 80)
}
.padding()
.background(Color.black.opacity(0.6))
.cornerRadius(10)
.foregroundColor(.white)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomLeading)
.padding()
Button(action: {
withAnimation {
tapCount += 1
}
}, label: {
ZStack {
Circle()
.foregroundStyle(Color.black.opacity(0.6))
.frame(width: 60, height: 60)
Circle()
.foregroundStyle(Color.black.opacity(0.6))
.frame(width: 80, height: 80)
}
})
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom)
.padding(.vertical)
.alert("result", isPresented: Binding<Bool>(
get: {
$length.wrappedValue != nil
},
set: { newValue in if !newValue {
$length.wrappedValue = nil
}
}
)) {
Button("re scan") {
length = nil
tapCount = 0
}
Button("register") {
bindLength = length
dismiss()
}
} message: {
if let length {
Text(
"""
result: \("\("\(String(format: "%0.1f", length)) cm")")
"""
)
}
}
}
.navigationTitle(
Text(title)
)
}
}