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()
}
}
}
Related
I want to open navigate to a view where I can add another picker option.
I tried the followings:
Picker(NSLocalizedString("Pick an option", comment: ""), selection: $value, content: {
ForEach(options, id: \.self){ option in
Text(option).tag(option)
}
Button(action: {
sheetIsPresented.toggle()
}, label: {
Image(systemName: "plus")
})
.sheet(isPresented: $sheetIsPresented){
AddView()
}
})
A button does show at the end of the options.
However, when the button is clicked, nothing happened. AddView() doesn't show up...
Is there a way to make this work?
try this approach, as shown in this example code:
struct ContentView: View {
#State var sheetIsPresented = false
#State var options = ["item-1","item-2","item-3"]
#State var value = "item-1"
var body: some View {
VStack (spacing: 88){
Picker(NSLocalizedString("Pick an option", comment: ""), selection: $value) {
ForEach(options, id: \.self){ option in
Text(option).tag(option)
}
}
Button(action: { sheetIsPresented.toggle() }) {
Image(systemName: "plus")
}
.sheet(isPresented: $sheetIsPresented) {
AddView(options: $options)
}
}
}
}
struct AddView: View {
#Binding var options: [String]
var body: some View {
// add some random option
Button(action: { options.append(UUID().uuidString) }) {
Image(systemName: "plus")
}
}
}
You can open a sheet with a menu if you put the .sheet on the menu element
example:
struct TestView: View {
#State var sheetIsPresented: Bool = false
var body: some View {
Menu("Actions") {
Button(action: {
sheetIsPresented.toggle()
}, label: {
Image(systemName: "plus")
})
}
.sheet(isPresented: $sheetIsPresented){
VStack{
Text("Hello")
}
}
}
}
Need help with this please.
I have a view with 2 date variables and I want to show a modal which have the datepicker and let user pick different dates for these variables.
Currently I have two buttons that show the same sheet but pass different variable to the modal.
The problem the variable don’t update after dismissing the modal.
import SwiftUI
#main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
import SwiftUI
struct ContentView: View {
#State private var secOneDate = Date()
#State private var secTwoDate = Date()
#State private var isDatepickerPresented = false
var body: some View {
VStack {
HStack{
Button{
isDatepickerPresented = true
} label: {
Image(systemName: "calendar")
.imageScale(.large)
.foregroundColor(.indigo)
}
.sheet(isPresented: $isDatepickerPresented){
DatePickView(selectDate: $secOneDate)
}
Text("SecOneDate: \(secOneDate.formatted(date: .abbreviated, time: .shortened))")
}
.padding()
HStack{
Button{
isDatepickerPresented = true
} label: {
Image(systemName: "calendar")
.imageScale(.large)
.foregroundColor(.mint)
}
.sheet(isPresented: $isDatepickerPresented)
{
DatePickView(selectDate: $secTwoDate)
}
Text("SecTwoDate: \(secTwoDate.formatted(date: .abbreviated, time: .shortened))")
}
.padding()
}
}
}
import SwiftUI
struct DatePickView: View {
#Environment(\.dismiss) private var dismiss
#Binding var selectDate: Date
var body: some View {
VStack(alignment: .center, spacing: 20) {
HStack {
Text("\(selectDate)")
.padding()
Spacer()
Button {
dismiss()
} label: {
Image(systemName: "delete.backward.fill")
.foregroundColor(.indigo)
}
}.padding()
DatePicker("", selection: $selectDate)
.datePickerStyle(.graphical)
}
}
}
First of all, thank you for your minimal, reproducible example: it is clear and can be immediately used for debugging. Answering to your question:
The problem with your code is that you have only one variable that opens the sheet for both dates. Even though you are correctly passing the two different #Bindings, when you toggle isDatepickerPresented you are asking SwiftUI to show both sheets, but this will never happen. Without knowing, you are always triggering the first of the sheet presentations - the one that binds secOneDate. The sheet that binds secTwoDate is never shown because you can't have two sheets simultaneously.
With that understanding, the solution is simple: use two different trigger variables. Here's the code corrected (DatePickView doesn't change):
struct Example: View {
#State private var secOneDate = Date()
#State private var secTwoDate = Date()
#State private var isDatepickerOnePresented = false
#State private var isDatepickerTwoPresented = false
var body: some View {
VStack {
HStack{
Button{
isDatepickerOnePresented = true
} label: {
Image(systemName: "calendar")
.imageScale(.large)
.foregroundColor(.indigo)
}
.sheet(isPresented: $isDatepickerOnePresented){
DatePickView(selectDate: $secOneDate)
}
Text("SecOneDate: \(secOneDate.formatted(date: .abbreviated, time: .shortened))")
}
.padding()
HStack{
Button{
isDatepickerTwoPresented = true
} label: {
Image(systemName: "calendar")
.imageScale(.large)
.foregroundColor(.mint)
}
.sheet(isPresented: $isDatepickerTwoPresented) {
DatePickView(selectDate: $secTwoDate)
}
Text("SecTwoDate: \(secTwoDate.formatted(date: .abbreviated, time: .shortened))")
}
.padding()
}
}
}
I'm trying to dismiss all active presented view controllers and pushed view controllers, but I'm facing some issue and not getting expected output.
ContentView -> Pushed(LoginView) -> Presented(HomeView) -> Expected back to (ContentView) directly without any animation lags and without showing intermediate animations. It should directly show content view.
here is my code:
import SwiftUI
struct FirstView: View {
#State var showLoginView = false
var body: some View {
NavigationView {
VStack(spacing: 16) {
Text("FirstView View")
.font(.largeTitle)
.foregroundColor(.red)
NavigationLink( destination: SecondView(), isActive: $showLoginView, label: {
Text("Show SecondView")
})
}
}
}
}
struct SecondView: View {
#State var showHomeView = false
#Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var body: some View {
VStack(spacing: 16) {
Text("Second View")
.font(.largeTitle)
.foregroundColor(Color(.systemPurple))
Button(action: { showHomeView = true }, label: {
Text("Show ThirdView")
.padding()
})
}
.sheet(isPresented: $showHomeView, onDismiss: { presentationMode.wrappedValue.dismiss() }) {
ThirdView()
}
}
}
struct ThirdView: View {
#Environment(\.presentationMode) var presentationMode
#State var showFormView = false
var body: some View {
VStack(spacing: 16) {
Text("Third View")
.font(.largeTitle)
.foregroundColor(Color(.systemTeal))
Button(action: {
showFormView = true
presentationMode.wrappedValue.dismiss()
}, label: {
Text("Back to FirstView")
.padding()
})
}
}
}
Hello, I want to navigate between windows using a button but not use a NavigationLink. It looks ugly.
this is my code
import SwiftUI
struct ContentView: View {
var body: some View {
Button(action: action()){
Text("Hola")
.font(.largeTitle)
.frame(width: 100, height: 100)
.background(Color.red)
}
}
}
You can use an empty NavigationLink and bind your navigation flag or destination to your Button.
struct FirstView: View {
#State var navigationFlag = false
var body: some View {
NavigationView {
VStack {
Text("First View")
Button(action: {
self.navigationFlag = true
}, label: {
Text("navigate")
})
NavigationLink(destination: SecondView(),
isActive: self.$navigationFlag,
label: {
EmptyView()
})
}
}
}
}
struct SecondView: View {
var body: some View {
Text("Second View")
}
}
I just shared this Bug with Apple. I want to share with you.
Application Follow
1 - After the user logs on to the onBoardingView page, they are directed to ContentView with fullScreenCover.
2 - ContentView page contains objects in TabView that are repeated with ForEach. Clicking on these objects will take you to the DetailView page.
3 - However, Navigation repeats itself several times after clicking the object.
My English is bad. Sorry for this.
Video is here
Project file is here
struct OnboardView: View {
#State var isLogin: Bool = false
var body: some View {
Button(action: {self.isLogin = true}) {
Text("Login")
}
.fullScreenCover(isPresented: self.$isLogin) {
ContentView()
}
}
}
struct ContentView: View {
#State var selected: String = ""
var items: [String] = ["1","2","3","4","5","6","7","8","9","10"]
var body: some View {
NavigationView {
TabView(selection: $selected) {
ForEach(items, id: \.self) { item in
NavigationLink(
destination: DetailView(),
label: {
Text(item)
.foregroundColor(.white)
.padding()
.background(Color.orange)
.cornerRadius(10)
})
}
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
}
}
}
When working with ForEach in SwiftUI, you have to be extra careful on the ids.
Try changing items to items.indices instead:
ForEach(items.indices, id: \.self) { item in
NavigationLink(
destination: Text("Detail View"),
label: {
Text(items[item])
.foregroundColor(.white)
.padding()
.background(Color.orange)
.cornerRadius(10)
}
)
}