SwiftUI Button Action - swiftui

I'm new to coding. Can someone please explain to me why this code doesn't work?
I'm trying to open a sheet when a button is tapped.
The button is part of a Floating Action Button like in Gmail with multiple options.
This 'SecondaryButton' is the options the user sees when the FAB is active.
Button(action: {
scanSheet.toggle()
}, label: {
//Scan Button
SecondaryButton(open: $open, icon: "camera.viewfinder", label: "Scan", color: "Blue", offsetY: -90)
.padding(.trailing, 40)
})
.sheet(isPresented: $scanSheet, content: {
Text("Hello")
})

I think that your SecondaryButton has something to do with this. I tested it without just a Text as label and it works.
Did you try to load a Button into the Label?
struct ContentView: View {
#State var scanSheet = false
var body: some View {
Button(action: {
scanSheet.toggle()
}, label: {
//Scan Button
Text("Button")
.padding(.trailing, 40)
})
.sheet(isPresented: $scanSheet, content: {
Text("Hello")
})
}
}

Related

Weird fullScreenCover and sheet behaviour in iOS 15

I have some problem with presenting sheet, sheet that use Identifiable item binding and fullScreenCover.
Main issue is that:
I choose identifiable item, corresponding sheet appears
I close that sheet with swipe
After it's dismiss i open normal sheet
It open again identifiable item sheet content
Another weird behaviour is if I open fullScreenCover after dismissing sheet it's open sheet but with content of fullScreenCover
This never happens on iOS 14. I think that is states that responsible for presenting those views not have time to update
You can checkout minimal gist reproduction or see it here
import SwiftUI
struct ContentView: View {
enum Sheet: String, Identifiable {
var id: String {
rawValue
}
case one, two
}
#State var isFullScreenPresented: Bool = false
#State var isSheetPresented: Bool = false
#State var isItemSheetPresented: Sheet?
var body: some View {
VStack {
HStack {
Button(action: {isFullScreenPresented.toggle()}, label: {
Text("fullScreen")
.padding()
.foregroundColor(.red)
.background(Rectangle())
})
Button(action: {isSheetPresented.toggle()}, label: {
Text("sheet")
.padding()
.foregroundColor(.red)
.background(Rectangle())
})
}
HStack {
Button(action: {isItemSheetPresented = .one}, label: {
Text("one")
.padding()
.foregroundColor(.red)
.background(Rectangle())
})
Button(action: {isItemSheetPresented = .two}, label: {
Text("two")
.padding()
.foregroundColor(.red)
.background(Rectangle())
})
}
HStack {
Text(isFullScreenPresented.description)
Text(isSheetPresented.description)
}
Text(isItemSheetPresented.debugDescription)
Spacer()
}
.sheet(item: $isItemSheetPresented, onDismiss: {isItemSheetPresented = nil}, content: {item in
Text(item.id)
})
.sheet(isPresented: $isSheetPresented, onDismiss: { isSheetPresented = false}, content: {
Text("sheet")
})
.fullScreenCover(isPresented: $isFullScreenPresented, onDismiss: {isFullScreenPresented = false }, content: {FullScreenContent()})
}
}
struct FullScreenContent: View {
#Environment(\.presentationMode) var dismiss
var body: some View {
VStack {
Button("close", action: {dismiss.wrappedValue.dismiss()})
Spacer()
}
}
}

If there a delayscontenttouches equivalent on SwiftUI ScrollView?

In SwiftUI, Buttons highlight on touch.
But when you place one into a ScrollView, it will also highlight when the user scrolls.
On UIKit, the delayscontenttouches UIScrollView's property exactly fixes this problem, but I haven't found a SwiftUI way to do it.
Here's some basic code that reproduces the problem.
ScrollView {
VStack {
Button(action: {
print("1")
}, label: {
Color.blue.frame(height: 300)
})
Button(action: {
print("2")
}, label: {
Color.blue.frame(height: 300)
})
Button(action: {
print("3")
}, label: {
Color.blue.frame(height: 300)
})
}
}

SwiftUI multiple sheets: dismiss animation broken

I have button1, showing sheet1 when pressed. Then I have a toggle, showing a button2, which in turn presents sheet2 when pressed.
If I just press button1, the sheet shows and dismisses with animation. If, however, I press the toggle, which shows button2, and then press button1, the sheet dismiss animation is broken (simply doesn't animate).
struct ContentView: View {
#State private var showSheetButton2 = false
#State private var showSheet1 = false
#State private var showSheet2 = false
var body: some View {
VStack {
Toggle("Show Sheet Button 2", isOn: $showSheetButton2)
Button(action: {
showSheet1.toggle()
}, label: {
Text("Show Sheet 1")
})
.sheet(isPresented: $showSheet1, content: {
Button(action: {
showSheet1 = false
}, label: {
Text("Dismiss")
})
})
if showSheetButton2 {
Button(action: {
showSheet2.toggle()
}, label: {
Text("Show Sheet 2")
})
.sheet(isPresented: $showSheet2, content: {
Button(action: {
showSheet2 = false
}, label: {
Text("Dismiss")
})
})
}
}.padding()
}
}
EDIT:
Fixed in iOS 14.5:
You can now apply multiple sheet(isPresented:onDismiss:content:) and
fullScreenCover(item:onDismiss:content:) modifiers in the same view
hierarchy. (74246633)
Somehow this sheet inside If statement is destroying animation. Please try to add EmptyView outside this if statement and assign sheet to that view.
if showSheetButton2 {
Button(action: {
showSheet2.toggle()
}, label: {
Text("Show Sheet 2")
})
}
EmptyView()
.sheet(isPresented: $showSheet2, content: {
Button(action: {
showSheet2 = false
}, label: {
Text("Dismiss")
})
})

Menu on NavigationLink is not tapable

How can I put a Menu on a NavigationLink destination? This approach opens only the destination and never the menu when I tap on it.
var body: some View {
NavigationView {
NavigationLink (
destination: Text("Hello")
label: {
ZStack(alignment: .topTrailing){
Rectangle()
.frame(width: 300, height: 100)
Menu {
Button("Order Now", action: {print("1")})
Button("Adjust Order", action: {print("2")})
} label: {
Label("Options", systemImage: "paperplane")
}
}
})
.buttonStyle(PlainButtonStyle())
}
}
EDIT: Just to clarify: The Menu is in the top right corner. When I tap on this menu button, the menu should appear. Otherwise when I tap on the rest of the view the destination of the NavigationLink should be opened
Okay.. third time's a charm.. so they say!
I made it harder than what it needed to be but that is a working example of Menu and I learned from this myself
import SwiftUI
struct navViewTest: View {
var body: some View {
NavigationView {
VStack {
Text("Hello World")
}.navigationBarItems(trailing:
Menu {
Button("Option 1", action: {doSomething() })
Button("Option 2", action: {doSomething() })
} label: {Text("Menu") }
)
}
}
private func doSomething() { }
}
struct navViewTest_Previews: PreviewProvider {
static var previews: some View {
navViewTest()
}
}
I've found a "solution". A little bit hacky, but it works so far. I just wrapped the menu in a button:
Button(action: {/*do something*/}, label: {
Menu {
Button("Option 1", action: {print("1") })
Button("Option 2", action: {print("2") })
} label: {Text("Menu") }
})

SwiftUI - Custom NavigationBar back button disables sliding gesture

I made my own back button in SwiftUI without using the navigation bar. Everything works very well. But when I switch from the first view to the second view, I cannot slide back. I shared my codes with you, my avalanche for your solution suggestions.
First View:
struct LogInView: View {
#State var showSignUpScreen = false
var body: some View {
NavigationView{
NavigationLink(
destination: SignUpView(),
isActive: self.$showSignUpScreen,
label: {
Text("")
})
Button(action: {
self.showSignUpScreen.toggle()
}, label: {
Text("Sign Up")
.fontWeight(.semibold)
.foregroundColor(.blue)
.frame(width: UIScreen.main.bounds.width * 0.3, height: UIScreen.main.bounds.height * 0.06)
.overlay(RoundedRectangle(cornerRadius: 10)
.stroke(Color.blue, lineWidth: 1.5))
.padding(.bottom, 15)
})
}
.navigationBarTitle("")
.navigationBarHidden(true)
}
}
Second View:
struct SignUpView: View {
#Environment(\.presentationMode) var present
var body: some View {
NavigationView{
Button(action: {
self.present.wrappedValue.dismiss()
}, label: {
ZStack {
Image(systemName: "chevron.backward")
.font(.system(size: 25, weight: .semibold))
.foregroundColor(.blue)
.padding(.leading, 10)
}
})
}
.navigationBarTitle("")
.navigationBarHidden(true)
}
}
Add this to your SignUpView:
init() {
UINavigationBar.appearance().isUserInteractionEnabled = false
UINavigationBar.appearance().backgroundColor = .clear
UINavigationBar.appearance().barTintColor = .clear
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
UINavigationBar.appearance().shadowImage = UIImage()
UINavigationBar.appearance().tintColor = .clear
}
And delete:
.navigationBarHidden(true)
The idea:
.navigationBarHidden(true) seems to not only hide the bar but also disable sliding. So, in order to be able to slide, we can't do that. Fourtunately, we can also just hide it globally using UINavigationBar.appearance(), without the need of .navigationBarHidden(true).
Note that if anywhere else inside your app you want the default UINavigationBar back, you would have to init() again and unhide it, since this sets the appearance globally.
I would recommend having a globally accessible function that contains the code to hide and unhide it if that's the case for you.