#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% …), Но я хочу, чтобы тело обновлялось, когда сегментированный сборщик (метрический <-> Имперский) имеет новую «позицию».