SwiftUI: представление не обновляет тело, когда сегментированный сборщик имеет новую позицию

#swift #swiftui

#swift #swiftui

Вопрос:

Мое приложение вычисляет для дайверов некоторые важные значения, такие как max. глубина и т. Д. В метрах или в футах. Вычисление записывается в отдельный файл. У меня проблема с переключателем сегментированного сборщика. Если я запускаю приложение, сегментированный сборщик (метрика <-> Imperial) находится в метрике. Когда я меняю сегментированный сборщик на Imperial, ничего не произошло. Но когда я нажимаю на кнопку и изменяю значение (32%, 33%) и нажимаю готово, результаты отображаются в футах. . Когда я меняю сегментированный сборщик обратно на метрику, снова ничего не произошло. Представление обновляется только при изменении значения (32%, 33%, …), но я хочу, чтобы тело обновлялось, когда сегментированный сборщик (Метрический <-> Имперский) имеет новую «позицию».

Пользовательский интерфейс приложения

введите описание изображения здесь

введите описание изображения здесь

    import SwiftUI
   import Combine

struct ContentView: View {
    
    @State var unitSelection = UserDefaults.standard.integer(forKey: "Picker")
    @State var O2_2 = 32
    @State var PO2_2 = 1.2
    
    var body: some View {
        ZStack {
            VStack {
                Picker("", selection: $unitSelection) {
                    Text("Metric").tag(0)
                    Text("Imperial").tag(1)
                }
                .pickerStyle(SegmentedPickerStyle()).padding(.horizontal, 89)
                .onReceive(Just(unitSelection)) {
                    UserDefaults.standard.set($0, forKey: "Picker")
                    switchMeasurement(measurement: $0)
                }
                Spacer()
            }
            BasicStructure(valueIndexO2Calculate_3: $O2_2, PO2_1: $PO2_2, unitSelection_1: unitSelection)
        }
    }
}

struct BasicStructure: View {
    //Variable from Picker: Calculate -> O2
    @Binding var valueIndexO2Calculate_3: Int
    @Binding var PO2_1: Double
     var unitSelection_1: Int
    
    var body: some View {
        VStack {
            HStack {
                Spacer()
            }
            Calculate(O2: $valueIndexO2Calculate_3, PO2: $PO2_1, unitSelection_2: unitSelection_1)
                
            ButtonMOD(valueIndexO2Calculate_2: self.$valueIndexO2Calculate_3, unitSelection_0: unitSelection_1)
            Spacer()
        }
    }
}

struct Calculate: View {
    @Binding var O2: Int
    @Binding var PO2: Double
    var unitSelection_2: Int
    
    var body: some View {
        VStack {
//O2 max. depth
            HStack (alignment: .center){
                VStack(alignment: .leading) {
                    Text("O2 max. depth")
                    Text("MOD O2")
                }
                Spacer()
                Text(calculateMod02(o2: self.O2, po2: Float(self.PO2)))
                    .padding(.trailing)
            }
                    .padding(.top).padding(.horizontal)
            Divider()
//eq. air depth
            HStack(alignment: .center) {
                VStack(alignment: .leading) {
                    Text("eq. air depth")
                    Text("EAD")
                }
                Spacer()
                Text(calculateEAD(o2: self.O2, po2: Float(self.PO2)))
                    .padding(.trailing)
            }
                    .padding(.horizontal)
            Divider()
//no deco time
            HStack(alignment: .center) {
                VStack(alignment: .leading) {
                    Text("no deco time")
                    Text("DECO 2000")
                }
                Spacer()
                Text("(calculateDeco2000(o2: self.O2, po2: Float(self.PO2)), specifier: "%.0f")'")
                    .padding(.trailing)
            }
                    .padding(.horizontal)
            Divider()
//max. dive time
            HStack(alignment: .center) {
                VStack(alignment: .leading) {
                    Text("max. dive time")
                    Text("CNS")
                }
                Spacer()
                Text("(calculateCNS(o2: self.O2, po2: Float(self.PO2)), specifier: "%.0f")'")
                    .padding(.trailing)
            }
                    .padding(.horizontal).padding(.bottom)
        }
        .padding()
    }
}

struct ButtonMOD: View {
    @State var showingDetail_O2 = false
    @State var showingDetail_PO2 = false
    //Variable from Picker: Calculate -> O2
    @Binding var valueIndexO2Calculate_2: Int
     var unitSelection_0: Int
    
    var body: some View {
    VStack {
        HStack(alignment: .center) {
            VStack(alignment: .leading) {
                Button(action: {
                    self.showingDetail_O2.toggle()
                }) {
                    Text("(self.valueIndexO2Calculate_2)%")
                    Text("O2")
                    }.sheet(isPresented: $showingDetail_O2) {
                        SheetViewO2(showSheetView: self.$showingDetail_O2, valueIndexO2Calculate_1: self.$valueIndexO2Calculate_2, unitSelection_3: self.unitSelection_0)
                    }
            }
        }
        }.padding()
        .padding()
    }
}

struct SheetViewO2: View {
    @Binding var showSheetView: Bool
    //Variable from Picker: Calculate -> O2
    @Binding var valueIndexO2Calculate_1: Int
     var unitSelection_3: Int
    
    var body: some View {
        NavigationView {
            ValueO2(valueIndexO2Calculate_0: $valueIndexO2Calculate_1, unitSelection_4: unitSelection_3)
                .navigationBarTitle(Text("Select value"), displayMode: .inline)
                .navigationBarItems(trailing: Button(action: {
                    self.showSheetView = false
                }) {
                    Text("Done")
                        .bold()
            })
        }.navigationViewStyle(StackNavigationViewStyle())
    }
}

//Show "Picker O2"
struct ValueO2: View {
    //Variable from Picker: Calculate -> O2
    @Binding var valueIndexO2Calculate_0: Int
     var unitSelection_4: Int
    
    @State var valueArray : [Int] = []
    
    var body: some View {
        VStack{
            Section {
                Text("O2")
                Picker("",selection: $valueIndexO2Calculate_0) {
                    ForEach(valueArray, id: .self){ value in
                        Text("(value) %")
                    }
                }
            }
            .labelsHidden()
        }.onAppear{
            self.initPickerIndex()
        }
    }
           func initPickerIndex(){
               
               valueArray = []
               
               for index1 in 21..<50 {
                   valueArray.append(index1)
               }
                          
               for index2 in 1...5{
                   valueArray.append(40   index2 * 10)
               }
           }
}
  

Ответ №1:

В этом сценарии вам не нужна привязка, используйте прямое значение для BasicStructure и ниже (т. е. Аналогично в подвидах), например

 BasicStructure(valueIndexO2Calculate_3: $O2_2, PO2_1: $PO2_2, 
   unitSelection_1: unitSelection)   // << here !!
  

и

 struct BasicStructure: View {
    //Variable from Picker: Calculate -> O2
    @Binding var valueIndexO2Calculate_3: Int
    @Binding var PO2_1: Double
    var unitSelection_1: Int        // << here !!
  

таким образом, изменение значения в сборщике приводит к обновлению тела и перестройке зависимых вложенных представлений.

Комментарии:

1. Хорошо, я меняю все привязки в прямых значениях, но это та же проблема, что и раньше. Тело обновляется только при изменении значения в сборщике (33%, 34% …), Но я хочу, чтобы тело обновлялось, когда сегментированный сборщик (метрический <-> Имперский) имеет новую «позицию».