SwiftUI 列出单个可选项目

col*_*ole 0 swiftui

我正在尝试创建一个List并允许一次仅选择一个项目。我将如何循环执行此操作ForEach?我可以很好地选择多个项目,但最终目标是在List. 这甚至可能不是处理我正在尝试的事情的正确方法。

struct ContentView: View {

    var body: some View {
        NavigationView {
            List((1 ..< 4).indices, id: \.self) { index in
                CheckmarkView(index: index)
                    .padding(.all, 3)
            }
            .listStyle(PlainListStyle())
            .navigationBarTitleDisplayMode(.inline)
            //.environment(\.editMode, .constant(.active))
        }
    }
}

struct CheckmarkView: View {
    let index: Int
    @State var check: Bool = false
    
    var body: some View {
        Button(action: {
            check.toggle()
        }) {
            HStack {
                Image("Image-\(index)")
                    .resizable()
                    .frame(width: 70, height: 70)
                    .cornerRadius(13.5)
                Text("Example-\(index)")
                Spacer()
                if check {
                    Image(systemName: "checkmark")
                        .resizable()
                        .frame(width: 12, height: 12)
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

jn_*_*pdx 5

您需要一些东西来存储所有状态,而不是存储每个复选标记视图,因为需要一次只检查一项。我做了一个小例子,其中逻辑在 an 中处理,并通过处理检查/取消检查状态的ObservableObject自定义传递到复选标记视图:Binding

struct CheckmarkModel {
    var id = UUID()
    var state = false
}

class StateManager : ObservableObject {
    @Published var checkmarks = [CheckmarkModel(), CheckmarkModel(), CheckmarkModel(), CheckmarkModel()]
    
    func singularBinding(forIndex index: Int) -> Binding<Bool> {
        Binding<Bool> { () -> Bool in
            self.checkmarks[index].state
        } set: { (newValue) in
            self.checkmarks = self.checkmarks.enumerated().map { itemIndex, item in
                var itemCopy = item
                if index == itemIndex {
                    itemCopy.state = newValue
                } else {
                    //not the same index
                    if newValue {
                        itemCopy.state = false
                    }
                }
                return itemCopy
            }
        }
    }
}

struct ContentView: View {
    @ObservedObject var state = StateManager()
    
    var body: some View {
        NavigationView {
            List(Array(state.checkmarks.enumerated()), id: \.1.id) { (index, item) in //<-- here
                CheckmarkView(index: index + 1, check: state.singularBinding(forIndex: index))
                    .padding(.all, 3)
            }
            .listStyle(PlainListStyle())
            .navigationBarTitleDisplayMode(.inline)
        }
    }
}

struct CheckmarkView: View {
    let index: Int
    @Binding var check: Bool //<-- Here
    
    var body: some View {
        Button(action: {
            check.toggle()
        }) {
            HStack {
                Image("Image-\(index)")
                    .resizable()
                    .frame(width: 70, height: 70)
                    .cornerRadius(13.5)
                Text("Example-\(index)")
                Spacer()
                if check {
                    Image(systemName: "checkmark")
                        .resizable()
                        .frame(width: 12, height: 12)
                }
            }
        }
    }
}

Run Code Online (Sandbox Code Playgroud)

发生了什么:

  1. 每个复选框都有一个CheckmarkModelID 以及该框的状态
  2. StateManager保留这些模型的数组。它还为数组的每个索引都有一个自定义绑定。对于getter,它仅返回该索引处模型的状态。对于setter,它会创建复选框数组的新副本。每当设置一个复选框时,它都会取消选中所有其他复选框。我也保留了你原有的不让任何检查的行为
  3. now获取-- usingList的枚举让我保留之前能够将索引号传递到复选框视图的行为state.checkmarksenumerated
  4. 在 ForEach 内部,创建之前的自定义绑定并将其传递给子视图
  5. 在子视图中,不使用@State,而是使用@Binding(这是自定义Binding传递给的)