私は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
カウントをデバッグしてログに出力しようとすると、正しい結果が出力されますが、UIは更新されません。
変更セグメント:
セグメントを最初に戻す:
任意の助けや提案をいただければ幸いです。
以前の2つの答えを組み合わせる:
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)
}
}
上記の回答は、SwiftUIのWheelpickerstyleでは機能しません。単位の数は初期値のままなので、温度から始めて長さに切り替えると、長さ配列の最後の2つの値が失われます。逆の場合、アプリは範囲外でクラッシュします。
解決策を見つけるのに永遠にかかりました。 Wheelpickerstyleのバグのようです。回避策は、ピッカーのIDを更新することです。これにより、すべてのデータソースを再ロードするように求められます。以下に例を示します。
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()
}
}