为什么带有按钮的快速导航列表会多次打开一个工作表而不是一次?

问题描述 投票:0回答:1

TLDR:在下面的代码中,单击顶层 ContentView 中的按钮会打开多个工作表,然后在关闭工作表时再次触发;但从 RowView 中单击它只会打开一张表。如何只从 ContentView 打开一张纸?

这是我所拥有的一个简单版本:带有项目列表的导航堆栈,每个项目都有一个可打开工作表的按钮。当拉出工作表时,它会运行一个任务来调用 Web 服务并检索一些要显示的数据。

问题是,根据我的调试,正在打开多个工作表,每个工作表都运行任务,并且有些工作表由于重复调用而失败。我想解决这个问题的方法是让工作表只出现一次。我怎样才能让它发挥作用?


import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationStack {
            List {
                NavigationLink {
                    Text("Hello")
                } label: {
                    RowView(textToShow: "Text 1")
                }
                NavigationLink {
                    Text("Hello")
                } label: {
                    RowView(textToShow: "Text 2")
                }
            }
        }
    }
}

struct RowView: View {
    var textToShow: String
    @State private var showingPopover = false
    
    var body: some View {
        Text("Hello")
        
        Button(action: {
            //showingPopover = true
            print("Button pressed")
        }, label: {
            Image(systemName:"doc.text")
                .imageScale(.large)
                
        })
        .onTapGesture {
            print("Button tapped")
            showingPopover = true
        }
        .sheet(isPresented: $showingPopover, content: {
            PopupView(textToShow: textToShow)
                .onAppear {
                    print("Sheet appeared")
                }
        })
    }
}

struct PopupView: View {
    var textToShow: String
    @State private var loading = true
    var body: some View {
        VStack {
            if loading {
                HStack{
                    ProgressView()
                    Text("Loading...")
                }
            } else {
                Text(textToShow)
            }
        }
        .onAppear() {
            print("Loading")
            loading = false
        }
    }
}

#Preview {
    ContentView()
}

#Preview {
    RowView(textToShow: "Text 1")
}

单击按钮,然后关闭工作表会在控制台中显示以下内容:

轻按按钮
加载中
表格出现了
加载中
表格出现了
加载中
表格出现了

我尝试使用状态变量来捕获弹出窗口何时已打开,然后仅在弹出窗口尚未打开时才显示工作表内容;我尝试仅在第一次点击手势时将绑定变量设置为

true
,但这也不是解决办法。

基于另一个类似的问题,我认为我需要将工作表向上移动,这对于捕获特定于行的文本来说有点棘手(我现在已经使用 swift 大约两周了?所以还没有完全习惯它)但我认为这可行

我期望只用一张表来加载并运行其任务。

swift swiftui task swiftui-navigationstack swiftui-ontapgesture
1个回答
0
投票

好吧,我想我找到了一个解决方案:通过将工作表移动到导航堆栈,它只出现一次。为了使注释来自与行相关的变量,我只使用绑定变量。在本例中,我使用了

isPresented
和一个单独的变量,但在我自己的情况下,我想我将使用
item
输入作为工作表。

import SwiftUI

struct ContentView: View {
    @State var showingPopover: Bool = false
    @State var textToShow: String = ""
    var body: some View {
        NavigationStack {
            List {
                NavigationLink {
                    Text("Hello")
                } label: {
                    RowView(showingPopover: $showingPopover, textToShow: $textToShow, textValue: "Text 1")
                }
                
                NavigationLink {
                    Text("Hello")
                } label: {
                    RowView(showingPopover: $showingPopover, textToShow: $textToShow, textValue: "Text 2")
                }
            }
        }
        .sheet(isPresented: $showingPopover, onDismiss: {
            print("Sheet dismissed")
            showingPopover = false
            textToShow = ""
        }, content: {
                PopupView(textToShow: textToShow)
                    .onAppear {
                        print("Popup appeared")
                    }
        })
    }
    
}

struct RowView: View {
    @Binding var showingPopover: Bool
    @Binding var textToShow: String
    var textValue: String
    
    var body: some View {
        Text("Hello")
        
        Button(action: {
            //showingPopover = true
            print("Button pressed")
        }, label: {
            Image(systemName:"doc.text")
                .imageScale(.large)
                
        })
        .onTapGesture {
            print("Button tapped")
            textToShow = textValue
            showingPopover = true
        }
        
    }
}

struct PopupView: View {
    var textToShow: String
    @State private var loading = true
    
    var body: some View {
        VStack {
            if loading {
                HStack{
                    ProgressView()
                    Text("Loading...")
                }
            } else {
                Text(textToShow)
            }
        }
        .onAppear() {
            print("Loading")
            loading = false
        }
    }
}

#Preview {
    ContentView()
}
© www.soinside.com 2019 - 2024. All rights reserved.