SwiftUI: средство выбора не обновляется правильно при изменении источника данных - PullRequest
3 голосов
/ 12 октября 2019

Я только начал изучать SwiftUI и где-то застрял!

Я пытаюсь изменить источник данных в стиле сегмента при изменении значения другого сегмента. Но почему-то это не работает, как ожидалось! Или я мог бы что-то не так кодировать. Может кто-нибудь разобраться, пожалуйста?

Вот мой кусок кода:

import SwiftUI

struct ContentView: View {    

@State var selectedType = 0
@State var inputUnit = 0
@State var outputUnit = 1

let arrTypes = ["Temperature", "Length"]

var arrData: [String] {
    switch self.selectedType {
    case 0:
        return ["Celsius", "Fahrenheit", "Kelvin"] //Temperature
    case 1:
        return ["meters", "kilometers", "feet", "yards", "miles"] //Length        
    default:
        return ["Celsius", "Fahrenheit", "Kelvin"]
    }        
}


var body: some View {
    NavigationView{
        Form
        {
            Section(header: Text("Choose type"))
            {
                Picker("Convert", selection: $selectedType) {
                    ForEach(0 ..< 2, id: \.self)
                    { i in
                        Text(self.arrTypes[i])
                    }
                }
                .pickerStyle(SegmentedPickerStyle())
            }

            Section(header: Text("From"))
            {
                Picker("", selection: $inputUnit) {
                    ForEach(0 ..< arrData.count, id: \.self)
                    {
                        Text(self.arrData[$0])
                    }
                }
                .pickerStyle(SegmentedPickerStyle())                    
            }

            Section(header: Text("To"))
            {
                Picker("", selection: $outputUnit) {
                    ForEach(0 ..< arrData.count, id: \.self)
                    {
                        Text(self.arrData[$0])
                    }
                }
                .pickerStyle(SegmentedPickerStyle())
            }                

        }
    }
}
}

Когда я меняю сегмент с Length на Temperature, он каким-то образом объединяет массив. Я попытался отладить и распечатать счет arrData в журнале, затем он выводит правильный результат, но не обновляет интерфейс!

Первый сегмент выбран по умолчанию: enter image description here

Изменить сегмент:

enter image description here

Изменить сегмент обратно на первый:

enter image description here

Любая помощь или предложениес благодарностью.

Ответы [ 3 ]

3 голосов
/ 13 октября 2019

Ник Полихронакис решил это в этом форке: https://github.com/nickpolychronakis/100DaysOfSwiftUI/tree/master/UnitCoverter

Решение состоит в том, чтобы добавить .id (: identifier :) к вашему средству выбора, чтобы он был уникальным.

Observable var:

@State var unit = 0

Основной сборщик:

Picker("Length", selection: $unit) {
                    ForEach(0 ..< inputUnitTypes.count) {
                        Text("\(self.inputUnitTypes[$0].description)")
                    }
                }
                .pickerStyle(SegmentedPickerStyle())

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

Picker("Length", selection: $inputUnit) {
                        ForEach(0 ..< selected.count) {
                            Text("\(self.selected[$0].description)")
                        }
                    }
                    .id(unit)
2 голосов
/ 12 октября 2019

Я не уверен, почему SwiftUI ведет себя так, мне кажется ошибкой (поправьте меня, если я ошибаюсь). Все, что я могу предложить, это добавить отдельные средства выбора для температуры и длины и скрыть те, которые основаны на текущем выбранном типе. Для повторного использования кода я добавил средство выбора в другой файл.

MyCustomPicker

struct MyCustomPicker: View {
    var pickerData: [String]
    @Binding var binding: Int
    var body: some View {
        Picker("Convert", selection: $binding) {
            ForEach(0 ..< pickerData.count, id: \.self)
            { i in
                Text(self.pickerData[i])
            }
        }
        .pickerStyle(SegmentedPickerStyle())
    }
}

ContentView

struct ContentView: View {

    @State var selectedType = 0
    @State var inputTempUnit = 0
    @State var outputTempUnit = 1
    @State var inputLenUnit = 0
    @State var outputLenUnit = 1

    let arrTypes = ["Temperature", "Length"]
    let tempData = ["Celsius", "Fahrenheit", "Kelvin"]
    let lenData  = ["meters", "kilometers", "feet", "yards", "miles"]


    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("Choose type")) {
                    MyCustomPicker(pickerData: arrTypes, binding: $selectedType)
                }

                Section(header: Text("From")) {
                    if selectedType == 0 {
                        MyCustomPicker(pickerData: tempData, binding: $inputTempUnit)
                    } else {
                        MyCustomPicker(pickerData: lenData, binding: $inputLenUnit)
                    }
                }

                Section(header: Text("To")) {
                    if selectedType == 0 {
                        MyCustomPicker(pickerData: tempData, binding: $outputTempUnit)
                    } else {
                        MyCustomPicker(pickerData: lenData, binding: $outputLenUnit)
                    }
                }
            }
        }
    }
}

Примечание: Вы должны использовать различные переменные состояния для отслеживания выбора температуры и длины.

0 голосов
/ 20 октября 2019

Объединение двух предыдущих ответов:

ContentView

    ...

    var units: [String] {
        symbols[unitType]
    }

    ...

            Section(header: Text("Unit Type")) {
                UnitPicker(units: unitTypes, unit: $unitType)
            }

            Section(header: Text("From Unit")) {
                UnitPicker(units: units, unit: $inputUnit)
                    .id(unitType)
            }

            Section(header: Text("To Unit")) {
                UnitPicker(units: units, unit: $outputUnit)
                    .id(unitType)
            }

    ...

UnitPicker

struct UnitPicker: View {
    var units: [String]

    @Binding var unit: Int

    var body: some View {
        Picker("", selection: $unit) {
            ForEach(units.indices, id: \.self) { index in
                Text(self.units[index]).tag(index)
            }
        }
        .pickerStyle(SegmentedPickerStyle())
        .font(.largeTitle)
    }
}

См. https://github.com/hugofalkman/UnitConverter.git

...