SwiftUI-绑定更改迫使NavigationView自动返回

时间:2020-09-23 15:12:51

标签: swiftui

在更改导航链接内部的绑定值时,我目前遇到问题。

数据结构如下:

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,请告诉我。

0 个答案:

没有答案