[英]Declaring TextField and Toggle in a SwiftUI dynamic form
4 年后我又回到了 Swift 編程,一切都變了。 我從頭開始學習一切。 我正在嘗試解決變量綁定問題。 我想構建一個動態表單,其中包含將從 API 返回的字段。 代碼:
import SwiftUI
struct Filter: Codable, Identifiable {
var id: Int
var name: String
var type: String
var defaultValue: Int
init(_ dictionary: [String: Any]) {
self.id = dictionary["id"] as? Int ?? 0
self.name = dictionary["name"] as? String ?? ""
self.type = dictionary["type"] as? String ?? ""
self.defaultValue = dictionary["defaultValue"] as? Int ?? 0
}
}
struct ContentView: View {
@State var filters:Array<Filter> = []
func load(){
guard let url = URL(string: "https://api.kierklosebastian.pl/") else {return}
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let dataResponse = data,
error == nil else {
print(error?.localizedDescription ?? "Response Error")
return }
do {
let decoder = JSONDecoder()
let model = try decoder.decode([Filter].self, from:
dataResponse)
self.filters = model;
} catch let parsingError {
print("Error", parsingError)
}
}
task.resume()
}
var body: some View {
VStack{
Button(action: self.load, label: {
Text("Get json")
})
List{
ForEach(self.filters) { filter in
HStack{
Text("NAME: \(filter.name)")
Text("TYPE: \(filter.type)")
if filter.type == "textField" {
// TextField("", ???????)
}
if filter.type == "checkbox" {
// Toggle(isOn: ????????) {
// ""
// }
}
}
}
}
}
}
}
如何聲明 TextFiled 和 Toggle 變量?
Toggle
需要有一個boolean
綁定屬性來確定切換是打開還是關閉。 所以你需要定義一個布爾屬性,例如,為Filter
。
struct Filter: Codable, Identifiable {
var id: Int
var name: String
var type: String
var defaultValue: Int
var isOn: Bool = false
init(_ dictionary: [String: Any]) {
self.id = dictionary["id"] as? Int ?? 0
self.name = dictionary["name"] as? String ?? ""
self.type = dictionary["type"] as? String ?? ""
self.defaultValue = dictionary["defaultValue"] as? Int ?? 0
self.isOn = (dictionary["type"] as? String ?? "") == "checkbox"
}
}
創建一個確認ObservableObject
的視圖模型。
https://developer.apple.com/documentation/combine/observableobject
class FilterViewModel: ObservableObject {
@Published var filters:Array<Filter> = []
func load(){
guard let url = URL(string: "https://api.kierklosebastian.pl/") else {return}
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let dataResponse = data,
error == nil else {
print(error?.localizedDescription ?? "Response Error")
return }
do {
let decoder = JSONDecoder()
let model = try decoder.decode([Filter].self, from:
dataResponse)
self.filters = model;
} catch let parsingError {
print("Error", parsingError)
}
}
task.resume()
}
}
並在ContentView
使用它代替@State var filters:Array<Filter> = []
。
struct FilterView: View {
@ObservedObject var viewModel = FilterViewModel()
-----
}
為ForEach
的內容創建一個新視圖,並將 viewModel 和過濾器傳遞給它。 在新視圖中,查找當前過濾器的索引。
struct FilterDetailView: View {
@ObservedObject var viewModel: FilterViewModel
var filter: Filter
var indexOfFilter: Int {
self.viewModel.filters.firstIndex { $0 == filter}!
}
var body: some View {
HStack{
Text("NAME: \(filter.name)")
Text("TYPE: \(filter.type)")
if filter.type == "textField" {
TextField("TextField", text: self.$viewModel.filters[indexOfFilter].name)
}
if filter.type == "checkbox" {
Toggle(isOn: self.$viewModel.filters[indexOfFilter].isOn) {
Text("Toggle")
}
}
}
}
}
您也需要向Equatable
確認。 否則,您不能使用firstIndex { $0 == filter}!
struct Filter: Codable, Identifiable, Equatable {
}
struct Filter: Codable, Identifiable, Equatable {
var id: Int
var name: String
var type: String
var defaultValue: Int
var isOn: Bool = false
init(_ dictionary: [String: Any]) {
self.id = dictionary["id"] as? Int ?? 0
self.name = dictionary["name"] as? String ?? ""
self.type = dictionary["type"] as? String ?? ""
self.defaultValue = dictionary["defaultValue"] as? Int ?? 0
self.isOn = (dictionary["type"] as? String ?? "") == "checkbox"
}
}
class FilterViewModel: ObservableObject {
@Published var filters:Array<Filter> = []
func load(){
guard let url = URL(string: "https://api.kierklosebastian.pl/") else {return}
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let dataResponse = data,
error == nil else {
print(error?.localizedDescription ?? "Response Error")
return }
do {
let decoder = JSONDecoder()
let model = try decoder.decode([Filter].self, from:
dataResponse)
self.filters = model;
} catch let parsingError {
print("Error", parsingError)
}
}
task.resume()
}
}
struct FilterView: View {
@ObservedObject var viewModel = FilterViewModel()
var body: some View {
VStack{
Button(action: self.viewModel.load, label: {
Text("Get json")
})
List{
ForEach(self.viewModel.filters) { filter in
FilterDetailView(viewModel: viewModel, filter: filter)
}
}
}
}
}
struct FilterDetailView: View {
@ObservedObject var viewModel: FilterViewModel
var filter: Filter
var indexOfFilter: Int {
self.viewModel.filters.firstIndex { $0 == filter}!
}
var body: some View {
HStack{
Text("NAME: \(filter.name)")
Text("TYPE: \(filter.type)")
if filter.type == "textField" {
TextField("TextField", text: self.$viewModel.filters[indexOfFilter].name)
}
if filter.type == "checkbox" {
Toggle(isOn: self.$viewModel.filters[indexOfFilter].isOn) {
Text("Toggle")
}
}
}
}
}
ForEach(self.viewModel.filters) { $filter in
-----
}
Toggle(isOn: $filter.isOn) {
Text("Toggle")
}
如果您有興趣,請觀看 SwiftUI 中的新增功能 - WWDC21 (08:00) 並關注 Apple 的 SwiftUI 教程
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.