Je viens de commencer à apprendre SwiftUI et je suis resté coincé quelque part!
J'essaie de changer la source de données du sélecteur de style de segment lors de la modification de la valeur d'un autre segment. Mais d'une manière ou d'une autre, cela ne fonctionne pas comme prévu! Ou bien j'aurais pu coder quelque chose de mal. Quelqu'un peut-il comprendre s'il vous plaît?
Voici mon morceau de code:
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())
}
}
}
}
}
Lorsque je change de segment de Length
en Temperature
, cela fusionne le tableau d'une manière ou d'une autre. J'ai essayé de déboguer et d'imprimer le compte arrData
dans le journal, puis il affiche le résultat correct mais ne met pas à jour l'interface utilisateur!
Premier segment sélectionné par défaut:
Changer de segment:
Remettez le segment en premier:
Toute aide ou suggestion serait grandement appréciée.
Combiner les deux réponses précédentes:
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)
}
}
Les réponses ci-dessus ne fonctionnent pas pour le Wheelpickerstyle dans SwiftUI. Le nombre d'unités restera à la valeur initiale, donc si vous commencez par Température puis passez à Longueur, il vous manquera les deux dernières valeurs du tableau Longueur. Si vous allez dans l'autre sens, votre application se bloquera avec une interdiction.
Il m'a fallu une éternité pour trouver une solution. Il semble que ce soit un bug dans le Wheelpickerstyle. La solution consiste à mettre à jour l'ID du sélecteur, ce qui l'invite à recharger toutes les sources de données. J'ai inclus un exemple ci-dessous.
import SwiftUI
// Data
struct Item: Identifiable {
var id = UUID()
var category:String
var item:String
}
let myCategories:[String] = ["Category 1","Category 2"]
let myItems:[Item] = [
Item(category: "Category 1", item: "Item 1.1"),
Item(category: "Category 1", item: "Item 1.2"),
Item(category: "Category 2", item: "Item 2.1"),
Item(category: "Category 2", item: "Item 2.2"),
Item(category: "Category 2", item: "Item 2.3"),
Item(category: "Category 2", item: "Item 2.4"),
]
// Factory
class MyObject: ObservableObject {
// Category picker variables
@Published var selectedCategory:String = myCategories[0]
@Published var selectedCategoryItems:[Item] = []
@Published var selectedCategoryInt:Int = 0 {
didSet {
selectCategoryActions(selectedCategoryInt)
}
}
// Item picker variables
@Published var selectedItem:Item = myItems[0]
@Published var selectedItemInt:Int = 0 {
didSet {
selectedItem = selectedCategoryItems[selectedItemInt]
}
}
@Published var pickerId:Int = 0
// Initial category selection
init() {
selectCategoryActions(selectedCategoryInt)
}
// Actions when selecting a new category
func selectCategoryActions(_ selectedCategoryInt:Int) {
selectedCategory = myCategories[selectedCategoryInt]
// Get items in category
selectedCategoryItems = myItems.filter{ $0.category.contains(selectedCategory)}
// Select initial item in category
let selectedItemIntWrapped:Int? = myItems.firstIndex { $0.category == selectedCategory }
if let selectedItemInt = selectedItemIntWrapped {
self.selectedItem = myItems[selectedItemInt]
}
self.pickerId += 1 // Hack to change ID of picker. ID is updated to force refresh
}
}
// View
struct ContentView: View {
@ObservedObject var myObject = MyObject()
var body: some View {
VStack(spacing: 10) {
Section(header: Text("Observable Object")) {
Text("Selected category: \(myObject.selectedCategory)")
Text("Items in category: \(myObject.selectedCategoryItems.count)")
Text("PickerId updated to force refresh \(myObject.pickerId)")
Text("Selected item: \(myObject.selectedItem.item)")
Picker(selection: self.$myObject.selectedCategoryInt, label: Text("Select category")) {
ForEach(0 ..< myCategories.count, id: \.self) {
Text("\(myCategories[$0])")
}
}.labelsHidden()
Picker(selection: self.$myObject.selectedItemInt, label: Text("Select object item")) {
ForEach(0 ..< self.myObject.selectedCategoryItems.count, id: \.self) {
Text("\(self.myObject.selectedCategoryItems[$0].item)")
}
}
.labelsHidden()
.id(myObject.pickerId) // Hack to get picker to reload data. ID is updated to force refresh.
}
Spacer()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}