Ios SwiftUI自定义列表无法在ForEach中使用绑定
我正在尝试构建一个自定义列表,用户可以在其中选择一个条目,该行将展开并显示一个选择器。此选择器应更新存储时间信息的对象(TimeItem) 但是,我无法在带有Picker的ForEach循环中使用绑定,我不知道为什么。Xcode中的错误消息是“编译器无法在合理的时间内对该表达式进行类型检查;请尝试将该表达式拆分为不同的子表达式” 我还尝试使用Ios SwiftUI自定义列表无法在ForEach中使用绑定,ios,swift,swiftui,Ios,Swift,Swiftui,我正在尝试构建一个自定义列表,用户可以在其中选择一个条目,该行将展开并显示一个选择器。此选择器应更新存储时间信息的对象(TimeItem) 但是,我无法在带有Picker的ForEach循环中使用绑定,我不知道为什么。Xcode中的错误消息是“编译器无法在合理的时间内对该表达式进行类型检查;请尝试将该表达式拆分为不同的子表达式” 我还尝试使用ForEach(Array(items.enumerated()),id:\.1)而不是ForEach(items)来获取当前行的索引,但这会弄乱删除动画(
ForEach(Array(items.enumerated()),id:\.1)
而不是ForEach(items)
来获取当前行的索引,但这会弄乱删除动画(但只是有时!?)
我不想对每一行使用相同的绑定(例如,self.$selectedElement.minutes
)-每一行都应该有自己的绑定
有人知道如何解决这个问题吗?谢谢你的帮助
class TimeItem: Identifiable, Equatable, ObservableObject {
static func == (lhs: TimeItem, rhs: TimeItem) -> Bool {
lhs.id == rhs.id
}
let id = UUID()
@Published var minutes: Int = 0
@Published var seconds: Int = 30
}
struct ContentView: View {
@State var items = [TimeItem]()
@State var selectedElement: TimeItem?
var body: some View {
ScrollView(){
VStack{
ForEach(items){ elem in
ZStack{
Rectangle()
.cornerRadius(12)
.frame(height: elem == selectedElement ? 120 : 40)
.foregroundColor(Color.gray.opacity(0.15))
Text("\(elem.minutes)")
.opacity(elem == selectedElement ? 0 : 1)
.transition(AnyTransition.scale)
if(elem == selectedElement){
HStack{
Picker(selection: elem.$minutes, label: Text("")){ // <- I can't use Binding with "elem"
ForEach(0..<60){ i in
Text("\(i)")
}
}
.frame(width: 120)
.clipped()
Picker(selection: .constant(0), label: Text("")){
ForEach(0..<60){ i in
Text("\(i)")
}
}
.frame(width: 120)
.clipped()
}
.frame(height: 120)
.clipped()
}
HStack{
Button(action: {
self.items.removeAll { $0.id == elem.id }
})
{
Image(systemName: "minus.circle.fill")
.foregroundColor(Color.red)
.font(.system(size: 22))
.padding(.leading, 10)
}
Spacer()
}
}
.padding(.horizontal)
.padding(.top)
.contentShape(Rectangle())
.onTapGesture {
withAnimation(.spring()){
self.selectedElement = elem
}
}
}
}
Spacer()
Button(action: {
self.items.append(TimeItem())
})
{
ZStack{
Rectangle()
.cornerRadius(12)
.frame(height: 40)
.foregroundColor(Color.gray.opacity(0.15))
Text("Add")
HStack{
Image(systemName: "plus.circle.fill")
.foregroundColor(Color.green)
.font(.system(size: 22))
.padding(.leading, 10)
Spacer()
}
}.padding()
}
}.animation(.spring(), value: items)
}
}
class时间项:可识别、可平衡、可观察的对象{
静态函数==(左:时间项,右:时间项)->Bool{
lhs.id==rhs.id
}
设id=UUID()
@发布的var分钟数:Int=0
@已发布变量秒数:Int=30
}
结构ContentView:View{
@状态变量项=[TimeItem]()
@状态变量selectedElement:TimeItem?
var body:一些观点{
ScrollView(){
VStack{
ForEach(项目){elem in
ZStack{
矩形()
.转弯半径(12)
.frame(高度:elem==selectedElement?120:40)
.前底色(颜色.灰色.不透明度(0.15))
文本(“\(元素分钟)”)
.不透明度(元素==selectedElement?0:1)
.transition(AnyTransition.scale)
if(elem==selectedElement){
HStack{
选择器(selection:elem.$minutes,label:Text(“”){/在这种情况下,您应该执行编译器所说的操作:将表达式(即大视图)分解为不同的子表达式(即较小的子视图)
以下是固定组件(使用Xcode 11.4/iOS 13.4测试)
struct ContentView:View{
@状态变量项=[TimeItem]()
@状态变量selectedElement:TimeItem?
var body:一些观点{
ScrollView(){
VStack{
ForEach(项目){elem in
ItemRowView(元素:元素,selectedElement:self.$selectedElement){
self.items.removeAll{$0.id==elem.id}
}
}
}
垫片()
AddItemView{
self.items.append(TimeItem())
}
}.animation(.spring(),值:items)
}
}
结构SelectedElementView:视图{
@观察对象变量元素:时间项
var body:一些观点{
HStack{
选择器(选择:$elem.minutes,标签:Text(“”)){
ForEach(0…)
var body:一些观点{
ZStack{
矩形()
.转弯半径(12)
.frame(高度:elem==selectedElement?120:40)
.前底色(颜色.灰色.不透明度(0.15))
文本(“\(元素分钟)”)
.不透明度(元素==selectedElement?0:1)
.transition(AnyTransition.scale)
if(elem==selectedElement){
SelectedElementView(元素:元素)
}
HStack{
按钮(操作:操作)
{
图像(系统名称:“减.圆.填充”)
.foregroundColor(颜色:红色)
.font(.system(大小:22))
.padding(.leading,10)
}
垫片()
}
}
.padding(.卧式)
.padding(.top)
.contentShape(矩形())
.ontapsigne{
使用动画(.spring()){
self.selectedElement=self.elem
}
}
}
}
很有趣!感谢您的帮助!我甚至没有想过将视图分解为子视图,因为对我来说,当代码出现其他错误时,通常会出现错误消息。
struct ContentView: View {
@State var items = [TimeItem]()
@State var selectedElement: TimeItem?
var body: some View {
ScrollView(){
VStack{
ForEach(items){ elem in
ItemRowView(elem: elem, selectedElement: self.$selectedElement){
self.items.removeAll { $0.id == elem.id }
}
}
}
Spacer()
AddItemView {
self.items.append(TimeItem())
}
}.animation(.spring(), value: items)
}
}
struct SelectedElementView: View {
@ObservedObject var elem: TimeItem
var body: some View {
HStack{
Picker(selection: $elem.minutes, label: Text("")){
ForEach(0..<60){ i in
Text("\(i)")
}
}
.frame(width: 120)
.clipped()
Picker(selection: .constant(0), label: Text("")){
ForEach(0..<60){ i in
Text("\(i)")
}
}
.frame(width: 120)
.clipped()
}
.frame(height: 120)
.clipped()
}
}
struct AddItemView: View {
let action: ()->()
var body: some View {
Button(action: action)
{
ZStack{
Rectangle()
.cornerRadius(12)
.frame(height: 40)
.foregroundColor(Color.gray.opacity(0.15))
Text("Add")
HStack{
Image(systemName: "plus.circle.fill")
.foregroundColor(Color.green)
.font(.system(size: 22))
.padding(.leading, 10)
Spacer()
}
}.padding()
}
}
}
struct ItemRowView: View {
@ObservedObject var elem: TimeItem
@Binding var selectedElement: TimeItem?
let action: ()->()
var body: some View {
ZStack{
Rectangle()
.cornerRadius(12)
.frame(height: elem == selectedElement ? 120 : 40)
.foregroundColor(Color.gray.opacity(0.15))
Text("\(elem.minutes)")
.opacity(elem == selectedElement ? 0 : 1)
.transition(AnyTransition.scale)
if(elem == selectedElement){
SelectedElementView(elem: elem)
}
HStack{
Button(action: action)
{
Image(systemName: "minus.circle.fill")
.foregroundColor(Color.red)
.font(.system(size: 22))
.padding(.leading, 10)
}
Spacer()
}
}
.padding(.horizontal)
.padding(.top)
.contentShape(Rectangle())
.onTapGesture {
withAnimation(.spring()){
self.selectedElement = self.elem
}
}
}
}