SwiftUI - Navigation bar button not clickable after sheet has been presented
I think this happens because the presentationMode
is not inherited from the presenter view, so the presenter didn't know that the modal is already closed. You can fix this by adding presentationMode
to presenter, in this case to ContentView.
struct ContentView: View {
@Environment(\.presentationMode) var presentation
@State var showSheet = false
var body: some View {
NavigationView {
VStack {
Text("Test")
}.sheet(isPresented: self.$showSheet) {
ModalView()
}.navigationBarItems(trailing:
Button(action: {
self.showSheet = true
}) {
Text("SecondView")
}
)
}
}
}
Tested on Xcode 12.5.
Here is the full working
example.
SwiftUI: Button in NavigationBar won't fire after modal dismissal
It is really a bug. The interesting thing is that after 'drag to dismiss' the issue is not observed, so it is a kind of 'sync/async' state changing or something.
Workaround (temporary of course, decreases visibility almost completely)
.navigationBarItems(trailing: Button(action: { self.displayModal = true }) {
Text("Add").padding([.leading, .vertical], 4)
})
SwiftUI button in navigation bar only works once
It's a known bug related to navigation bar items and not relegated to just sheets, it seems to affect any modal, and I've encountered it in IB just the same when using modal segues.
Unfortunately this issue is still present in 11.3 build, hopefully they get this fixed soon.
SwiftUI Button not responding when added Padding to it
to be clear this is the code I'm using for testing:
@main
struct TestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContactView: View {
@Binding var isContactViewActive: Bool
@State var searchBar = ""
var backgroundColor = Color(red: 14/255, green: 18/255, blue: 23/255, opacity: 1.0)
var body: some View {
NavigationView {
ZStack {
backgroundColor
VStack {
HStack {
Button(action: {print("magnifyingglass")}, label: {
Image(systemName: "magnifyingglass").font(.title)
})
Spacer()
Text("FireChat")
.font(.title)
.fontWeight(.light)
.foregroundColor(Color.white)
Spacer()
Button(action: {print("power")}, label: {
Image(systemName: "power").font(.title)
})
}.padding(.top, 50)
}
}.edgesIgnoringSafeArea(.all)
}
}
}
struct ContentView: View {
@State var isContactViewActive = false
var body: some View {
ContactView(isContactViewActive: $isContactViewActive)
}
}
SwiftUI - in sheet have a fixed continue button that is not scrollable
Here is a demo of possible approach (tuning & effects are out of scope - try to make demo code short). The idea is to inject UIView
holder with button above sheet so it persist during sheet drag down (because as findings shown any dynamic offsets gives some ugly undesired shaking effects).
Tested with Xcode 12 / iOS 14
// ... your above code here
}//VStack for 3 criterias
.padding([.leading, .trailing], 20)
Spacer()
// button moved from here into below background view !!
}.background(BottomView(presentation: presentationMode) {
Button {
presentationMode.wrappedValue.dismiss()
UserDefaults.standard.set(true, forKey: "LaunchedBefore")
} label: {
Text("Continue")
.fontWeight(.medium)
.padding([.top, .bottom], 15)
.padding([.leading, .trailing], 90)
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(15)
}
})
//Main VStack
}
}
struct BottomView<Content: View>: UIViewRepresentable {
@Binding var presentationMode: PresentationMode
private var content: () -> Content
init(presentation: Binding<PresentationMode>, @ViewBuilder _ content: @escaping () -> Content) {
_presentationMode = presentation
self.content = content
}
func makeUIView(context: Context) -> UIView {
let view = UIView()
DispatchQueue.main.async {
if let window = view.window {
let holder = UIView()
context.coordinator.holder = holder
// simple demo background to make it visible
holder.layer.backgroundColor = UIColor.gray.withAlphaComponent(0.5).cgColor
holder.translatesAutoresizingMaskIntoConstraints = false
window.addSubview(holder)
holder.heightAnchor.constraint(equalToConstant: 140).isActive = true
holder.bottomAnchor.constraint(equalTo: window.bottomAnchor, constant: 0).isActive = true
holder.leadingAnchor.constraint(equalTo: window.leadingAnchor, constant: 0).isActive = true
holder.trailingAnchor.constraint(equalTo: window.trailingAnchor, constant: 0).isActive = true
if let contentView = UIHostingController(rootView: content()).view {
contentView.backgroundColor = UIColor.clear
contentView.translatesAutoresizingMaskIntoConstraints = false
holder.addSubview(contentView)
contentView.topAnchor.constraint(equalTo: holder.topAnchor, constant: 0).isActive = true
contentView.bottomAnchor.constraint(equalTo: holder.bottomAnchor, constant: 0).isActive = true
contentView.leadingAnchor.constraint(equalTo: holder.leadingAnchor, constant: 0).isActive = true
contentView.trailingAnchor.constraint(equalTo: holder.trailingAnchor, constant: 0).isActive = true
}
}
}
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
if !presentationMode.isPresented {
context.coordinator.holder.removeFromSuperview()
}
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
class Coordinator {
var holder: UIView!
deinit {
holder.removeFromSuperview()
}
}
}
Related Topics
Make Code With Firebase Asynchronous
Swift Spritekit Adding Button Programmatically
How to Use the Appropriate Color Class For the Current Platform
Select() from Linq in Swift 3.0
How to Make Class Methods/Properties in Swift
Dispatchsourcetimer and Swift 3.0
Class 'Viewcontroller' Has No Initializers in Swift
Simpliest Solution to Check If File Exists on a Webserver. (Swift)
Check Whether Swift Object Is an Instance of a Given Metatype
Swift Sphere Combine Star Data
Retrieving Image from Firebase Storage Using Swift
Pass Variables from One Viewcontroller to Another in Swift
Swiftui - Passing Data from Swiftuiview to Scenekit
Add Subtitle Under the Title in Navigation Bar Controller in Xcode
Programmatically Navigate to New View in Swiftui
Intrinsiccontentsize() - Method Does Not Override Any Method from Its Superclass
How to Detect a Swiftui Touchdown Event with No Movement or Duration