SwiftUI:从详图修改主视图
我想用swiftUI编写我的第一个iOS应用程序。我有很多编程经验,但都是很久以前的事了。我以为我能很快学会斯威夫特,但我错了。世界变了 我有一个包含参与者列表的主视图(一个称为“ActivePerson”的数组),每个参与者都有一个详细视图(“EditPerson”),该视图允许修改参与者或从列表中删除参与者。要添加新人员,列表中的最后一项不是人员,而是指向允许选择新人员的详细视图(“NewPerson”)的符号 目前,我已将人员列表定义为全局变量。当然,这不会导致主视图更新 我尝试过使用@State包装器,但所有尝试都失败了。当然,我可以在ContentView中将activePersons定义为一个状态变量,但是我不能从细节视图中修改它 非常感谢您的帮助 以下是我的代码(摘录): 而ContentView.swift的内容如下:SwiftUI:从详图修改主视图,swiftui,Swiftui,我想用swiftUI编写我的第一个iOS应用程序。我有很多编程经验,但都是很久以前的事了。我以为我能很快学会斯威夫特,但我错了。世界变了 我有一个包含参与者列表的主视图(一个称为“ActivePerson”的数组),每个参与者都有一个详细视图(“EditPerson”),该视图允许修改参与者或从列表中删除参与者。要添加新人员,列表中的最后一项不是人员,而是指向允许选择新人员的详细视图(“NewPerson”)的符号 目前,我已将人员列表定义为全局变量。当然,这不会导致主视图更新 我尝试过使用@S
import SwiftUI
struct ContentView: View {
var body: some View {
TabView {
NavigationView {
List {
ForEach(0..<activePersons.count, id: \.self) { value in
NavigationLink(
destination: EditPerson(),
label: {
VStack (alignment: .leading) {
Text(activePersons[value].name)
.font(.system(size: 26, weight: .regular))
}.padding(15)
})
}
NavigationLink(
destination: NewPerson(),
label: {
Image(systemName: "person.crop.circle.badge.plus")
.font(.system(size: 26, weight: .light))
.foregroundColor(Color(red: 0.7, green: 0.7, blue: 0.7))
.padding(15)
})
}.environment(\.defaultMinListRowHeight, 30)
.navigationTitle("Participants")
}
.tabItem{
Image(systemName: "square.and.pencil")
Text("Planning")
}
...
导入快捷界面
结构ContentView:View{
var body:一些观点{
TabView{
导航视图{
名单{
ForEach(0..通常,您需要使用绑定或observeObject将状态向下传递到子视图中。下面的代码说明了这两种情况:
struct Person: Identifiable, Hashable {
let id: Int
var name: String
}
class AppState : ObservableObject {
@Published var activeIds : [Int] = [0,1]
@Published var persons: [Person] = [Person(id: 0, name: "Dummy1"),
Person(id: 1, name: "Dummy2"),
Person(id: 2, name: "Dummy3"),
Person(id: 3, name: "Dummy4")]
var activePersons : [Person] {
return activeIds.compactMap { id in
persons.first(where: { $0.id == id
})
}
}
var nonActivePersons : [Person] {
persons.filter { !activeIds.contains($0.id) }
}
func bindingForId(id: Int) -> Binding<Person> {
.init { () -> Person in
self.persons.first(where: { $0.id == id }) ?? Person(id: -1, name: "()")
} set: { (newValue) in
self.persons = self.persons.map {
if $0.id == id {
return newValue
} else {
return $0
}
}
}
}
}
struct ContentView: View {
@StateObject var state = AppState()
var body: some View {
TabView {
NavigationView {
List {
ForEach(state.activePersons, id: \.self) { person in
NavigationLink(
destination: EditPerson(person: state.bindingForId(id: person.id)),
label: {
VStack (alignment: .leading) {
Text(person.name)
.font(.system(size: 26, weight: .regular))
}.padding(15)
})
}
NavigationLink(
destination: NewPerson(state: state),
label: {
Image(systemName: "person.crop.circle.badge.plus")
.font(.system(size: 26, weight: .light))
.foregroundColor(Color(red: 0.7, green: 0.7, blue: 0.7))
.padding(15)
})
}.environment(\.defaultMinListRowHeight, 30)
.navigationTitle("Participants")
}
.tabItem{
Image(systemName: "square.and.pencil")
Text("Planning")
}
}
}
}
struct EditPerson : View {
@Binding var person : Person
var body: some View {
TextField("name", text: $person.name)
}
}
struct NewPerson: View {
@ObservedObject var state : AppState
var body: some View {
List {
ForEach(state.nonActivePersons, id: \.self) { person in
Button(action: {
state.activeIds.append(person.id)
}) {
Text(person.name)
}
}
}.environment(\.defaultMinListRowHeight, 30)
}
}
结构人:可识别、可散列{
让id:Int
变量名称:String
}
类AppState:ObservableObject{
@已发布的var-activeIds:[Int]=[0,1]
@已发布var人员:[人员]=[人员(id:0,名称:“Dummy1”),
此人(id:1,姓名:“Dummy2”),
此人(id:2,姓名:“Dummy3”),
人员(身份证号码:3,姓名:“Dummy4”)]
个人:[个人]{
返回activeIds.compactMap{id
persons.first(其中:{$0.id==id
})
}
}
变量非活动人员:[人]{
persons.filter{!activeIds.contains($0.id)}
}
func bindingForId(id:Int)->Binding{
.init{()->中的个人
Person.first(其中:{$0.id==id})?Person(id:-1,名称:“()”)
}集合:{(newValue)在
self.persons=self.persons.map{
如果$0.id==id{
返回新值
}否则{
返回$0
}
}
}
}
}
结构ContentView:View{
@StateObject变量state=AppState()
var body:一些观点{
TabView{
导航视图{
名单{
ForEach(state.activePersons,id:\.self){person in
导航链接(
目标:EditPerson(person:state.bindingForId(id:person.id)),
标签:{
VStack(对齐:。前导){
文本(person.name)
.font(.system(大小:26,重量:常规))
}.填充(15)
})
}
导航链接(
目的地:NewPerson(州:州),
标签:{
图像(系统名称:“person.crop.circle.badge.plus”)
.font(.system(大小:26,重量:轻))
.foregroundColor(颜色(红色:0.7,绿色:0.7,蓝色:0.7))
.填充(15)
})
}.environment(\.defaultMinListRowHeight,30)
.navigationTitle(“参与者”)
}
.tabItem{
图像(系统名称:“正方形和铅笔”)
文本(“规划”)
}
}
}
}
结构编辑人员:视图{
@个人:个人
var body:一些观点{
TextField(“name”,text:$person.name)
}
}
结构NewPerson:View{
@ObservedObject变量状态:AppState
var body:一些观点{
名单{
ForEach(state.nonActivePersons,id:\.self){person in
按钮(操作:{
state.activeIds.append(person.id)
}) {
文本(person.name)
}
}
}.environment(\.defaultMinListRowHeight,30)
}
}
在本例中,我正在创建一个名为AppState
的observeObject。它具有@Published属性--@Published将在值发生更改时发出刷新视图的信号()
您可以看到,当调用NewPerson
时,整个state对象作为参数传递给它
对于EditPerson
视图,我只将绑定
传递给Person
——绑定允许在SwiftUI中进行双向通信()
因为您有一个人的数组
,所以我必须做一些工作才能获得直接绑定,除非您想使用数组索引,因为数组索引有点脆弱。您可以在函数bindingForId
中看到我如何获得基于id的绑定
我还有活动人员
和非活动人员
的计算属性——当其中一个@已发布的
值发生更改时,这些计算属性将重新计算
你可能会发现我的另一个答案是:这很好用,谢谢!但是,有一件事还不完美:当我选择一个新的人时,视图临时切换到父视图,然后再次切换到新的人视图。就我而言,完美的选择是,在我选择了一个新的人之后,视图更改以编辑此人的视图。是否可以从一个详细视图切换到另一个详细视图?
import SwiftUI
struct NewPerson: View {
@State var name: String = ""
var body: some View {
List {
ForEach(0..<otherPersons.count) { value in
Button(action: {
activePersons.append(otherPersons[value])
}) {
Text(otherPersons[value].name)
}
}
}.environment(\.defaultMinListRowHeight, 30)
}
}
struct Person: Identifiable, Hashable {
let id: Int
var name: String
}
class AppState : ObservableObject {
@Published var activeIds : [Int] = [0,1]
@Published var persons: [Person] = [Person(id: 0, name: "Dummy1"),
Person(id: 1, name: "Dummy2"),
Person(id: 2, name: "Dummy3"),
Person(id: 3, name: "Dummy4")]
var activePersons : [Person] {
return activeIds.compactMap { id in
persons.first(where: { $0.id == id
})
}
}
var nonActivePersons : [Person] {
persons.filter { !activeIds.contains($0.id) }
}
func bindingForId(id: Int) -> Binding<Person> {
.init { () -> Person in
self.persons.first(where: { $0.id == id }) ?? Person(id: -1, name: "()")
} set: { (newValue) in
self.persons = self.persons.map {
if $0.id == id {
return newValue
} else {
return $0
}
}
}
}
}
struct ContentView: View {
@StateObject var state = AppState()
var body: some View {
TabView {
NavigationView {
List {
ForEach(state.activePersons, id: \.self) { person in
NavigationLink(
destination: EditPerson(person: state.bindingForId(id: person.id)),
label: {
VStack (alignment: .leading) {
Text(person.name)
.font(.system(size: 26, weight: .regular))
}.padding(15)
})
}
NavigationLink(
destination: NewPerson(state: state),
label: {
Image(systemName: "person.crop.circle.badge.plus")
.font(.system(size: 26, weight: .light))
.foregroundColor(Color(red: 0.7, green: 0.7, blue: 0.7))
.padding(15)
})
}.environment(\.defaultMinListRowHeight, 30)
.navigationTitle("Participants")
}
.tabItem{
Image(systemName: "square.and.pencil")
Text("Planning")
}
}
}
}
struct EditPerson : View {
@Binding var person : Person
var body: some View {
TextField("name", text: $person.name)
}
}
struct NewPerson: View {
@ObservedObject var state : AppState
var body: some View {
List {
ForEach(state.nonActivePersons, id: \.self) { person in
Button(action: {
state.activeIds.append(person.id)
}) {
Text(person.name)
}
}
}.environment(\.defaultMinListRowHeight, 30)
}
}