在更改导航链接内部的绑定值时,我目前遇到问题。
数据结构如下:
internal struct DailyNutritionReportElement: Identifiable, Hashable, Codable {
internal var id: UUID
internal var amount: Double
internal var comment: String
internal var dailyNutritionReportMO: DailyNutritionReport?
internal var dailyNutritionReportElementTypeMO: DailyNutritionReportElementType
internal var isDone: Bool
}
然后在主视图中,在ScrollView中显示不同的元素:
ScrollView {
VStack(spacing: 15) {
ForEach(self.viewModel
.dailyNutritionReports[self.selectedReportIndex]
.dailyNutritionReportElementMO,
id: \.self) { element in
ReportElementItem(
viewModel: self.viewModel,
element: element,
selectedReportIndex: self.selectedReportIndex
)
}
}
}
对于每个元素,我都会显示一个ReportElementItem
,如下所示:
struct ReportElementItem: View {
@ObservedObject var viewModel: HomeViewVielModel
@State var element: DailyNutritionReportElement
@State private var isChecked: Bool = false
var selectedReportIndex: Int
var body: some View {
if element.dailyNutritionReportElementTypeMO.dailyNutritionReportElementUnitMO.abbreviation == "Y/N" {
BooleanReportElementItem(
typeDescription: element.dailyNutritionReportElementTypeMO.typeDescription,
icon: element.dailyNutritionReportElementTypeMO.dailyNutritionReportElementTypeIconMO,
toggleState: self.getToggleBinding()
)
}
if element.dailyNutritionReportElementTypeMO.dailyNutritionReportElementUnitMO.abbreviation != "Y/N" {
MeasureableReportElement(
icon: element.dailyNutritionReportElementTypeMO.dailyNutritionReportElementTypeIconMO,
typeDescription: element.dailyNutritionReportElementTypeMO.typeDescription,
amount: self.amountBinding(),
target: element.dailyNutritionReportElementTypeMO.dailyTarget,
unit: element.dailyNutritionReportElementTypeMO.dailyNutritionReportElementUnitMO
)
}
}
private func amountBinding() -> Binding<Double> {
Binding(
get: { element.amount },
set: {
element.amount = $0
self.viewModel.updateDailyNutritionReportElement(element: element)
}
)
}
private func getToggleBinding() -> Binding<Bool> {
Binding<Bool>(
get: { self.element.isDone },
set: {
self.element.isDone = $0
self.viewModel.updateDailyNutritionReportElement(element: element)
}
)
}
}
在其中显示一个MeasureableReportElement
,它看起来像这样:
{
@State var icon: DailyNutritionReportElementTypeIcon
@State var typeDescription: String
@Binding var amount: Double
@State var target: Double
@State var unit: DailyNutritionReportElementUnit
var body: some View {
NavigationLink(
destination: ProgressBar(
progress: $amount,
target: target,
typeDescription: typeDescription
)
) {
Group {
VStack(spacing: 10) {
Text(typeDescription)
.foregroundColor(Color.label)
.font(.system(size: 20))
HStack {
Text("\(String(format: "%.2f", amount))")
Text("von")
Text("\(String(format: "%.2f", target))")
Text(unit.name)
}
.foregroundColor(Color.label)
}
Spacer()
}
.cardified(with: icon)
}
}
}
最后,我在其中通过NavigationLink导航到ProgressBar
,如下所示:
struct ProgressBar: View {
@Binding var progress: Double
@State var target: Double
@State var typeDescription: String
@State var rotationAngle: Angle = Angle.degrees(0)
@Environment(\.colorScheme) var colorScheme: ColorScheme
var body: some View {
VStack {
if self.isTargetReached() {
Text("You did it ??")
.font(.system(size: 30))
.padding(.top, 30)
}
ZStack {
Circle()
.fill(self.isTargetReached() ? Color.green : Color.systemBackground)
Circle()
.stroke(lineWidth: 20.0)
.opacity(0.3)
.foregroundColor(self.getCircleColor())
Circle()
.trim(
from: 0.0,
to: CGFloat(min(self.progress / self.target, 1.0))
)
.stroke(
style: StrokeStyle(
lineWidth: 20.0,
lineCap: .round,
lineJoin: .round
)
)
.foregroundColor(self.getCircleColor())
.rotationEffect(Angle(degrees: 270.0))
VStack {
if self.isTargetReached() {
Image(systemName: "checkmark.circle")
.font(.system(size: 120))
.foregroundColor(isTargetReached() ? Color.white : Color.label)
}
HStack {
Text("\(String(format: "%.2f", self.progress))")
Text("/")
Text("\(String(format: "%.2f", self.target))")
}
.animation(.none)
.padding()
.foregroundColor(isTargetReached() ? Color.white : Color.label)
}
.font(.largeTitle)
}
.padding()
.rotationEffect(self.rotationAngle)
HStack {
Spacer()
Circle()
.frame(
width: 80,
height: 80,
alignment: .center
)
.overlay(
Image(systemName: "minus")
.font(.system(size: 30))
.foregroundColor(.white)
)
.foregroundColor(.red)
.onTapGesture {
if self.progress > 0 {
withAnimation(.default) {
self.progress -= 0.25
}
}
}
Spacer()
Circle()
.frame(
width: 80,
height: 90,
alignment: .center
)
.overlay(
Image(systemName: "plus")
.font(.system(size: 30))
.foregroundColor(.white)
)
.foregroundColor(getCircleColor())
.onTapGesture {
withAnimation(.default) {
self.progress += 0.25
}
if target == progress {
withAnimation {
self.rotationAngle += Angle.degrees(360)
}
}
}
Spacer()
}
.padding(.bottom, 50)
}
.navigationBarTitle("\(typeDescription)", displayMode: .inline)
}
private func isTargetReached() -> Bool {
self.progress >= self.target ? true : false
}
private func getCircleColor() -> Color {
isTargetReached() ? Color.green : Color.blue
}
}
每次我按下ProgressBar-View
中的一个按钮时,progress
的值都会改变,从而绑定element.amount
中的ReportElementItem
值。这部分的工作原理与预期的一样。
现在我不了解的部分:
每次我按下ProgressBar-View
中的一个按钮时,导航会自动跳回到上一步,并且视图消失。当我使用sheet
而不是NavigationLink
时,也会发生同样的情况,而我听不懂。
有人知道这个问题吗?我希望我的描述足够详细。如果有人需要更多代码或问题的视频/ gif,请告诉我。