swift - 如何使用 SwiftUI 制作单选列表
问题描述
我正在创建单个选择列表以在我的应用程序的不同位置使用。
问题:
有没有我不知道的简单解决方案?
如果没有,我该如何完成当前的解决方案?
我的目标:
- 始终只选择一项或一项或一项未选择的列表(取决于配置)
- 透明背景
- 在项目选择上 - 执行通过 init() 方法设置为参数的操作。(该操作需要选定的项目信息。)
- 以编程方式更改列表数据并将选择重置为第一项
我当前的解决方案如下所示: 选择第二项的列表视图
我不能使用 Picker,因为外部操作(目标编号 3)非常耗时。所以我认为它不会顺利进行。很可能在 SwiftUI 中有解决我的问题的方法,但是我错过了它,因为我是 swift 新手,或者据我所知,SwiftUI 中的所有内容都不能完美运行,例如:List 的透明背景(这就是为什么我需要清除init()) 中的背景。
所以我开始自己实现选择,并停在这里:单击项目(按钮)时,我当前的解决方案不会更新视图。(仅外出并返回页面更新视图)。并且仍然可以选择多个项目。
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 数组并将其绑定到可能更新视图的 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"
]
解决方案
实现这一点的最简单方法是在包含带有选择的列表的视图中使用@State,并将其作为@Binding 传递给单元格:
struct SelectionView: View {
let fruit = ["apples", "pears", "bananas", "pineapples"]
@State var selectedFruit: String? = nil
var body: some View {
List {
ForEach(fruit, id: \.self) { item in
SelectionCell(fruit: item, selectedFruit: self.$selectedFruit)
}
}
}
}
struct SelectionCell: View {
let fruit: String
@Binding var selectedFruit: String?
var body: some View {
HStack {
Text(fruit)
Spacer()
if fruit == selectedFruit {
Image(systemName: "checkmark")
.foregroundColor(.accentColor)
}
} .onTapGesture {
self.selectedFruit = self.fruit
}
}
}
推荐阅读
- c++ - 简单的游戏,while 循环和检查字符串
- reactjs - React Context 不适用于服务器端渲染
- c# - 多线程网络应用程序问题
- javascript - jquery可折叠菜单仅在移动设备上滚动时打开
- python - Discord.py 表情符号 400
- python-3.x - OCR文字识别
- c++ - c++多态中实例的构造函数和析构函数
- javascript - 当一个特定的 div 命中它,或者它距离顶部 100px 时,如何让我的固定标题滚动
- flutter - 获取用于重建的 ErrorWidget 大小
- c++ - 如果 C/C++ 指针“只是”地址,为什么它们需要有一个类型?