我正在创建单个选择列表,以在应用程序的不同位置使用。
问题:
我不知道有没有简单的解决方法?
如果没有。如何完成当前的解决方案?
我的目标:
我当前的解决方案如下:List view with second item selected
我不能使用Picker,因为外部动作(目标3)非常耗时。因此,我认为它将无法顺利进行。最有可能在SwiftUI中解决了我的问题,但是我错过了它,因为我是Swift的新手,或者据我所知,并不是所有东西都可以在SwiftUI中完美运行,例如:List的透明背景(这就是为什么我需要清除init()中的背景。
所以我开始自己实施选择,并在此处停止:当单击item(Button)时,我当前的解决方案不更新视图。 (仅外出并返回页面更新视图)。而且仍然可以选择多个项目。
import SwiftUI
struct ModuleList: View {
var modules: [Module] = []
@Binding var selectionKeeper: Int
var Action: () -> Void
init(list: [Module], selection: Binding<Int>, action: @escaping () -> Void) {
UITableView.appearance().backgroundColor = .clear
self.modules = list
self._selectionKeeper = selection
self.Action = action
}
var body: some View {
List(){
ForEach(0..<modules.count) { i in
ModuleCell(module: self.modules[i], action: { self.changeSelection(index: i) })
}
}.background(Constants.colorTransparent)
}
func changeSelection(index: Int){
modules[selectionKeeper].isSelected = false
modules[index].isSelected = true
selectionKeeper = index
self.Action()
}
}
struct ModuleCell: View {
var module: Module
var Action: () -> Void
init(module: Module, action: @escaping () -> Void) {
UITableViewCell.appearance().backgroundColor = .clear
self.module = module
self.Action = action
}
var body: some View {
Button(module.name, action: {
self.Action()
})
.frame(minWidth: 0, maxWidth: .infinity, alignment: .center)
.modifier(Constants.CellSelection(isSelected: module.isSelected))
}
}
class Module: Identifiable {
var id = UUID()
var name: String = ""
var isSelected: Bool = false
var address: Int
init(name: String, address: Int){
self.name = name
self.address = address
}
}
let testLines = [
Module(name: "Line1", address: 1),
Module(name: "Line2", address: 3),
Module(name: "Line3", address: 5),
Module(name: "Line4", address: 6),
Module(name: "Line5", address: 7),
Module(name: "Line6", address: 8),
Module(name: "Line7", address: 12),
Module(name: "Line8", address: 14),
Module(name: "Line9", address: 11),
Module(name: "Line10", address: 9),
Module(name: "Line11", address: 22)
]
[尝试在ModuleList中添加(isSelected:Bool)的@State数组并将其绑定到MIGHT更新视图的Module isSelected参数...但是失败,然后在init()中填充此数组,因为@State数组参数在之后将保持为空。 append()...也许添加函数setList可以解决此问题,而我的目标是Nr。 4.但是我不确定这是否真的会更新我的观点。
struct ModuleList: View {
var modules: [Module] = []
@State var selections: [Bool] = []
init(list: [String]) {
UITableView.appearance().backgroundColor = .clear
selections = [Bool] (repeating: false, count: list.count) // stays empty
let test = [Bool] (repeating: false, count: list.count) // testing: works as it should
selections = test
for i in 0..<test.count { // for i in 0..<selections.count {
selections.append(false)
modules.append(Module(name: list[i], isSelected: $selections[i])) // Error selections is empty
}
}
var body: some View {
List{
ForEach(0..<modules.count) { i in
ModuleCell(module: self.modules[i], action: { self.changeSelection(index: i) })
}
}.background(Constants.colorTransparent)
}
func changeSelection(index: Int){
modules[index].isSelected = true
}
}
struct ModuleCell: View {
var module: Module
var Method: () -> Void
init(module: Module, action: @escaping () -> Void) {
UITableViewCell.appearance().backgroundColor = .clear
self.module = module
self.Method = action
}
var body: some View {
Button(module.name, action: {
self.Method()
})
.frame(minWidth: 0, maxWidth: .infinity, alignment: .center)
.modifier(Constants.CellSelection(isSelected: module.isSelected))
}
}
struct Module: Identifiable {
var id = UUID()
var name: String = ""
@Binding var isSelected: Bool
init(name: String, isSelected: Binding<Bool>){
self.name = name
self._isSelected = isSelected
}
}
let testLines = ["Line1","Line2","Line3","Line4"
]
SwiftUI当前没有内置的方法来选择列表的一行并相应地更改其外观。但是您实际上非常接近您的答案。实际上,您的选择实际上已经在起作用,但是没有任何使用。
为了说明,请在ModuleCell(...)
中的ForEach
之后添加以下行:
.background(i == self.selectionKeeper ? Color.red : nil)
换句话说,“如果我当前行(i
)与selectionKeeper
中存储的值匹配,则将单元格涂成红色,否则,使用默认颜色。”您会看到,当您点击不同的行时,红色跟随您的点击,表明底层的选择实际上正在改变。
如果要启用取消选择,可以传入Binding<Int?>
作为选择,并在点击当前选定的行时将其设置为nil
:
struct ModuleList: View {
var modules: [Module] = []
// this is new ------------------v
@Binding var selectionKeeper: Int?
var Action: () -> Void
// this is new ----------------------------v
init(list: [Module], selection: Binding<Int?>, action: @escaping () -> Void) {
...
func changeSelection(index: Int){
if selectionKeeper != index {
selectionKeeper = index
} else {
selectionKeeper = nil
}
self.Action()
}
}
从结构上讲,在使用像SwiftUI这样的声明性UI框架时,您真的想要一个真实的来源,并将视图与模型完全分开。目前,您有重复的状态-selectionKeeper
中的ModuleList
和isSelected
中的Module
都跟踪是否选择了给定的模块。
此外,isSelected实际上应该是视图(ModuleCell
)的属性,而不是模型(Module
)的属性,因为它与视图的外观有关,而不是每个模块的固有数据。] >
因此,您的ModuleCell
应该看起来像这样:
struct ModuleCell: View { var module: Module var isSelected: Bool // Added this var Action: () -> Void // Added this -------v init(module: Module, isSelected: Bool, action: @escaping () -> Void) { UITableViewCell.appearance().backgroundColor = .clear self.module = module self.isSelected = isSelected // Added this self.Action = action } var body: some View { Button(module.name, action: { self.Action() }) .frame(minWidth: 0, maxWidth: .infinity, alignment: .center) .modifier(Constants.CellSelection(isSelected: isSelected)) // Changed this ------------------------------^ } }
并且您的
ForEach
看起来像
ForEach(0..<modules.count) { i in
ModuleCell(module: self.modules[i],
isSelected: i == self.selectionKeeper,
action: { self.changeSelection(index: i) })
}