【发布时间】:2021-06-13 00:13:43
【问题描述】:
使用iOS14.4、Swift5.3.2、XCode12.2,
我尝试关闭 SwiftUI 的 GridView(参见下面的代码)。
dismiss函数由@Environmentas explained here的\.presentationMode属性完成。
在我引入 @Binding 属性之前一切正常,该属性会在解雇的那一刻改变父视图。 (见下面代码摘录中的dataStr = titles[idx])。
我读到\.presentationMode 的解雇只有在子视图显示期间父视图未更新时才有效。
但是当用户在这里点击 GridView 的一个元素时,我绝对需要在父视图上引起突变。
如何重新编写以便更新父视图并且解除子视图仍然有效?
struct GridView: View {
@Environment(\.presentationMode) private var presentationMode
@Binding var dataStr: String
@State private var titles = [String]()
let layout = [
GridItem(.flexible()),
GridItem(.flexible())
]
var body: some View {
ScrollView {
LazyVGrid(columns: layout, spacing: 10) {
ForEach(titles.indices, id: \.self) { idx in
VStack {
Text(titles[idx])
Image(titles[idx])
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: (UIScreen.main.bounds.width / 2) - 40)
}
.onTapGesture {
// WITHOUT THIS LINE OF CODE - EVERYTHING WORKS. WHY???????????????
dataStr = titles[idx]
self.presentationMode.wrappedValue.dismiss()
}
}
}
.padding()
}
}
}
正如@jnpdx 所问,在这里您可以看到父视图。请在ToolBarItem()的.sheet()中找到GridView(dataStr: self.$dataStr)....
import SwiftUI
struct MainView: View {
@EnvironmentObject var mediaViewModel: MediaViewModel
@EnvironmentObject var commService: CommunicationService
@State private var dataStr = ""
@State private var connectionsLabel = ""
@State private var commumincationRole: THRole = .noMode
@State private var showingInfo = false
@State private var showingGrid = false
init() {
UINavigationBar.appearance().tintColor = UIColor(named: "title")
}
var body: some View {
NavigationView {
if mediaViewModel.mediaList.isEmpty {
LoadingAnimationView()
.navigationBarHidden(true)
.ignoresSafeArea()
} else {
if dataStr.isEmpty {
MainButtonView(dataStr: $dataStr,
commumincationRole: $commumincationRole,
connectionsLabel: $connectionsLabel
)
.navigationBarHidden(false)
.navigationTitle("Trihow Pocket")
.navigationBarColor(backgroundColor: UIColor(named: "btnInactive"), titleColor: UIColor(named: "title"))
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: {
showingInfo.toggle()
}) {
Image(systemName: "ellipsis")
}
.sheet(isPresented: $showingInfo) {
InfoView()
}
}
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {
showingGrid.toggle()
}) {
Image(systemName: "square.grid.3x3")
}
.sheet(isPresented: $showingGrid) {
// GRIDVIEW CALLING THE CHILD-VIEW IS HERE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
GridView(dataStr: self.$dataStr)
}
}
}
} else {
let str = self.dataStr
#if os(iOS)
PageViewiOS(dataStr: self.$dataStr, commumincationRole: $commumincationRole)
.navigationBarHidden(true)
.onAppear() {
if commumincationRole == .moderatorMode {
commService.send(thCmd: THCmd(key: .tagID, sender: "", content: str))
}
}
.ignoresSafeArea()
#elseif os(macOS)
PageViewMacOS()
.ignoresSafeArea()
#endif
}
}
}
.onTHComm_PeerAction(service: commService) { (peers) in
let idsOrNames = peers.map { (peer) -> String in
if let id = peer.id {
return "\(id)"
} else if let name = peer.name {
return "\(name)"
} else {
return ""
}
}
connectionsLabel = "Connected devices: \n\(idsOrNames.lineFeedString)"
}
.onTHComm_ReceiveCmd(service: commService) { (thCmd) in
if (commumincationRole == .moderatorMode) || (commumincationRole == .discoveryMode) {
switch thCmd.key {
case .tagID:
dataStr = thCmd.content
case .closeID:
dataStr = ""
default:
break
}
}
}
.onTHComm_LastMessageLog(service: commService) { (log) in
print(log)
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
struct MainView_Previews: PreviewProvider {
static var previews: some View {
MainView()
.environmentObject(MediaViewModel())
.environmentObject(MultipeerConnectivityService())
}
}
【问题讨论】:
-
了解您最初是如何呈现此视图的可能会有所帮助(来自父级)
-
@jnpdx,我添加了父视图(...是的,它相当复杂)...
-
嗯。没有立即看到任何东西,但是没有可测试的代码很难。如果你在
DispatchQueue.main.async {}中封装了dismiss 电话会怎样? -
是的,
async不起作用 - 但使用asyncAfter它起作用了!!!即我将dataStr = thumNames[idx]包裹在DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(50)) {...}中,现在它消失了。问题仍然存在,如果父更新不能像我的示例一样在最后完成怎么办?当父视图发生更新时,SwiftUI 似乎有一个问题。其他人描述了它here -
你得到什么错误?您是否尝试过使用简单的 Text() 视图而不是 PageViewiOS?我已经做了。它奏效了。