I have a main View with a NavigationView which can present a sheet. The sheet has also a NavigationView. The sheet can be dismissed with gesture but not with self.presentationMode.wrappedValue.dismiss()
If a remove the NavigationView from the sheet, it is correctly dismissed.
Could you please advise?
Code for the sheet
var body: some View {
NavigationView{
VStack{
SheetTitleView(imageName:"gear", title:"Paramètres")
Divider().padding(.top, -10)
Form{...}
Spacer()
}.navigationBarTitle("").navigationBarHidden(true).statusBar(hidden: false)
}.edgesIgnoringSafeArea(.top)
}
struct SheetTitleView: View{
#Environment(\.colorScheme) var colorScheme: ColorScheme
#Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var imageName:String
var title:String
var body: some View {
ZStack{
if (self.colorScheme == ColorScheme.light){
Color(UIColor.systemGray4).edgesIgnoringSafeArea(.all)
} else{
Color(UIColor.systemGray6).edgesIgnoringSafeArea(.all)
}
VStack{
HStack(){
Image(systemName: self.imageName).font(Font.system(.title)).foregroundColor(Color(UIColor.darkGray)).padding(.leading, 10)
Text(self.title).foregroundColor(Color(UIColor.darkGray)).font(.title).bold()
Spacer()
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Image(systemName: "xmark.circle.fill").foregroundColor(Color(UIColor.darkGray)).font(.title).padding(.trailing, 10)
}
}
}
}.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 60, alignment: .topLeading)
}
}
Related
Having issues with a NavigationView and Sheet.
I want to use not full-size sheet but bottom sheet and connect LoginView() and SignView() through sheet. At this time, frame of SignView never follow sheet.
So I tried two ways to solve.
First, LoginView: Has NavigationView out of the sheet and NavigationLink in sheet . But it didn't work.
So I put NavigationView in sheet, it works. But the height of the destination View becomes like sheet.
How can I solve the problem proper way? Thanks!
import SwiftUI
struct LoginView:View{
#State var isPlus : Bool = false
var body: some View{
NavigationView{
VStack(alignment:.center){
Spacer()
ZStack{
Button(action:{
self.isPlus = true})
{
Text("Sign up")
.padding(.horizontal,23)
.padding(20)
.font(.system(size: 25))
.fontWeight(.heavy)
.background(Color.blue)
.foregroundColor(Color.white)
.cornerRadius(10)
}
.sheet(isPresented: $isPlus){
VStack{
NavigationLink(destination:SignView()){
Text("MyCard")
.font(.title)
.foregroundColor(Color.black)
}
}
.presentationDetents([.height(300)])
}
}
}
}
}
}
Hope you can get solution from the below code snippet.
By this way we can use sheet in the NavigationView.
struct LoginView: View {
#State var isPlus : Bool = false
#State private var showingSheet = false
var body: some View {
NavigationView {
VStack(alignment:.center) {
Spacer()
ZStack{
Button(action:{
self.isPlus = true})
{
Text("First Sheet View")
.padding(.horizontal,23)
.padding(20)
.font(.system(size: 25))
.background(Color.blue)
.foregroundColor(Color.white)
.cornerRadius(10)
}
.sheet(isPresented: $isPlus){
VStack{
NavigationView {
NavigationLink(destination:SignView()){
Button(action:{
self.showingSheet = true})
{
Text("Full Sheet View")
.padding(.horizontal,23)
.padding(20)
.font(.system(size: 25))
.background(Color.blue)
.foregroundColor(Color.white)
.cornerRadius(10)
}
.sheet(isPresented: $showingSheet){
Button("Close"){
showingSheet = false
isPlus = false
}
.presentationDetents([.large])
}
}
}
.presentationDetents([.medium])
.edgesIgnoringSafeArea(.all)
}
}
}
}
}
}
}
I have a strange behavior.
When I close my fullScreenCover, I have no animation on it. On the other hand, I have the animation at the opening. I don't understand why I have no close animation.
Example codes
import SwiftUI
struct ContentView: View {
#EnvironmentObject var myViewModel: MyViewModel
private var gridItemLayout = [GridItem(.flexible()), GridItem(.flexible())]
var body: some View {
ScrollView {
LazyVGrid(columns: gridItemLayout, spacing: 10) {
ForEach(myViewModel.data, id: \.self) { data in
ChildView(data: data)
}
}
}
.onAppear() {
self.myViewModel.getData()
}
.navigationBarTitle("My ContentView")
}
}
import SwiftUI
struct ChildView: View {
#State var data: Data
#State var showModal = false
var body: some View {
Button(action: {
self.showModal.toggle()
}, label: {
VStack {
Text("\(data.name)")
.font(.body)
.frame(width: 180, height: 150/2, alignment: .bottom)
VStack {
Text("\(Image(systemName: "checkmark.bubble")) 15")
Text("\(Image(systemName: "clock")) 20'")
}
.frame(width: 180, height: 150/2, alignment: .bottomTrailing)
}
.cornerRadius(10)
.frame(minWidth: 0, maxWidth: 180, minHeight: 150, maxHeight: 150, alignment: .center)
})
.fullScreenCover(isPresented: $showModal) {
OtherView()
}
}
}
import SwiftUI
struct OtherView: View {
#Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView {
VStack {
Button {
presentationMode.wrappedValue.dismiss()
} label: {
HStack {
Text("CLOSE")
Spacer()
Image(systemName: "checkmark")
.resizable()
.frame(width: 30, height: 30)
.padding()
}
}
}
.navigationBarTitle("My Modal", displayMode: .inline)
}
}
}
Thanks.
been searching for this everywhere and can't find anything around this, I believe is a bug, maybe is not.
I need NavigationView with .navigationViewStyle(.stack) to have it stacked on the iPad and make it look the same as the iphone, now suppose you have this view:
import SwiftUI
struct ContentView: View {
#State var isShowingProfile = false
#State var isNavigationViewShowing = true
var body: some View {
if isNavigationViewShowing {
NavigationView {
VStack {
Button("Simple view") {
isNavigationViewShowing = false
}
.padding()
Button("Profile navigation") {
isShowingProfile = true
}
.padding()
NavigationLink(
destination: ProfileView(),
isActive: $isShowingProfile
) {
EmptyView()
}
}
.frame(
minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity
)
.background(Color.gray)
.navigationBarHidden(true)
}
.navigationViewStyle(.stack)
} else {
VStack {
Button("Show NavigationView"){
isNavigationViewShowing = true
}
.padding()
}
.frame(
minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity
).background(Color.yellow)
}
}
}
struct ProfileView: View {
var body: some View {
Text("This is a profile")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Well this just show this 3 simple views:
The navigationView when you start
The Profile view if you tap on "Profile navigation"
Finally the Simple view which is trigger by the conditional state pressing "Simple view"
Up to here is all fine and good.
The problem is when navigate to the "Simple view" and then tap "Show NavigationView" to navigate back to the NavigtionView.
The app opens the first view (NavigationView), but the NavigationView ignores the .navigationBarHidden(true) and just show a big empty space on the top. In fact, it would ignore things like .navigationBarTitleDisplayMode(.inline) and just show the large version of the navigationBar
This is working correctly in all iOS 14.x, but on iOS 15.0 seems broken. The behaviour continues to be the same on iOS 15.1 beta.
Any idea whats going on? I'm not really interested in changing the conditionals on the view, because real life app is more complex.
Also, I tried ViewBuilder without any success. And if I take out .navigationViewStyle(.stack) it works all fine on iOS 15, but then the view on the iPad is with the side menu.
Thanks a lot for any tip or help, you should be able to reproduce in simulator and real device.
Video of the explained above
I think the better solution all around is to not have the NavigationView be conditional. There is no reason your conditional can't just live in the NavigationView. You just don't ever want the bar to show. Therefore, this code would seem to meet the requirements:
struct ContentView: View {
#State var isShowingProfile = false
#State var isNavigationViewShowing = true
var body: some View {
NavigationView {
Group {
if isNavigationViewShowing {
VStack {
Button("Simple view") {
isNavigationViewShowing = false
}
.padding()
Button("Profile navigation") {
isShowingProfile = true
}
.padding()
NavigationLink(
destination: ProfileView(),
isActive: $isShowingProfile
) {
EmptyView()
}
}
.frame(
minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity
)
.background(Color(UIColor.systemGray6))
} else {
VStack {
Button("Show NavigationView"){
isNavigationViewShowing = true
}
.padding()
}
.frame(
minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity
).background(Color.yellow)
}
}
.navigationBarHidden(true)
}
.navigationViewStyle(.stack)
}
}
I used Group simply to put the .navigationBarHidden(true) in the correct place so the code would compile.
Is this the behavior you are looking for?
import SwiftUI
struct ContentView: View {
#State private var isShowingProfile = false
#State private var showSimple = false
var body: some View {
NavigationView {
VStack {
Button("Simple view") {
showSimple = true
}
.padding()
Button("Profile navigation") {
isShowingProfile = true
}
.padding()
NavigationLink(destination: ProfileView(), isActive: $isShowingProfile) {
EmptyView()
}
}
.fullScreenCover(isPresented: $showSimple, onDismiss: {
print("Dismissed")
}, content: {
SimpleView()
})
.frame(
minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity
)
.background(Color.gray)
.navigationBarHidden(true)
}
.navigationViewStyle(.stack)
}
}
struct ProfileView: View {
var body: some View {
Text("This is a profile")
}
}
struct SimpleView: View {
#Environment(\.presentationMode) var presentationMode
var body: some View {
VStack {
Button("Show NavigationView") {
presentationMode.wrappedValue.dismiss()
}
.padding()
}
.frame(
minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity
).background(Color.yellow)
}
}
So i want my keyboard to overlay the view so that the view stays and not going upwards. i did several variations such as adding it in my loginstuff, or adding in it navigationView. it doesn't work at all
Here's my code
struct LoginView: View {
#StateObject var userData = UserData()
var body: some View {
NavigationView {
ZStack(alignment:.top) {
Color.pink.ignoresSafeArea(edges: .top)
VStack {
Image(systemName: "graduationcap.fill")
.resizable()
.scaledToFit()
.frame(width: /*#START_MENU_TOKEN#*/100/*#END_MENU_TOKEN#*/, height: /*#START_MENU_TOKEN#*/100/*#END_MENU_TOKEN#*/, alignment: /*#START_MENU_TOKEN#*/.center/*#END_MENU_TOKEN#*/)
.foregroundColor(.white)
.padding(.top,30)
Text("Study +")
.font(.title)
.fontWeight(.medium)
.foregroundColor(.white)
Spacer()
//Mark : The login Thinggy
LoginStuffs()
}
}
.edgesIgnoringSafeArea(.bottom)
.navigationTitle("Login")
.navigationBarHidden(true)
}
}
}
Login Stuff
struct LoginStuffs: View {
#State var username:String = ""
#State var password:String = ""
#State var isShow:Bool = false
var body: some View {
Vstack{
Textfield()
Securefield()
Securefield()
}
.padding()
.frame(width:UIScreen.width,height:UIScreen.height/1.5)
.background(Color.white)
.cornerRadius(15, corners: [.topLeft, .topRight])
//.ignoresSafeArea(edges: /*#START_MENU_TOKEN#*/.bottom/*#END_MENU_TOKEN#*/)
}
}
Seems like there's a problem within my codes in which I did not know (probably due to not learn it properly). please do help, thank you for your attention
use on your NavigationView
.edgesIgnoringSafeArea(.bottom))
I am trying to add some filter options to sit at the top of my view, above the NavigationView. I wrote the following code that mostly does what I want, however it disabled the ability to click on the rows to get to the detailed view. I assume this is because my filter buttons are on top of the ZStack, but I'm not sure how else to get this to work.
Here is the code I wrote:
import SwiftUI
struct BonusList: View {
var bonuses = sampleBonusData
#State var showSettings = false
#State var showBonuses = false
#State var bonusEarned = true
#State var showStatePicker = false
#State var showCategoryPicker = false
var body: some View {
ZStack {
NavigationView {
List(bonuses) { item in
NavigationLink(destination: BonusDetail(bonusName: item.bonusName, bonusCode: item.bonusCode, city: item.city, sampleImage: item.sampleImage)) {
HStack(spacing: 12.0) {
Image(item.sampleImage)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 60, height: 60)
.background(Color.white)
.cornerRadius(15)
VStack(alignment: .leading) {
HStack {
Text(item.bonusName)
.font(.headline)
Spacer()
Image(systemName: "checkmark.shield")
.opacity(self.bonusEarned ? 100 : 0)
}
Text("\(item.city), \(item.state)")
.font(.subheadline)
.frame(height: 25.0)
HStack {
Text(item.bonusCategory)
.font(.caption)
.fontWeight(.bold)
.foregroundColor(.gray)
.padding(.top, 4)
Spacer()
Text(item.bonusCode)
.font(.caption)
.fontWeight(.bold)
.foregroundColor(.gray)
.padding(.top, 4)
}
}
}
}
}
.navigationBarTitle(Text("Bonuses"))
// .navigationBarHidden(true)
}
.saturation(self.bonusEarned ? 0 : 1)
HStack {
FilterByCategory(showCategoryPicker: $showCategoryPicker)
Spacer()
FilterByState(showStatePicker: $showStatePicker)
}
StatePicker(showStatePicker: $showStatePicker)
CategoryPicker(showCategoryPicker: $showCategoryPicker)
}
}
}
This is what it looks like when I run it:
If I'm understanding correctly, you have a view or two which sit higher in the ZStack that are off canvas and come in when those buttons are tapped?
You could consider using a modal and setting the view you want to show for each button as the view for the modal. This will keep your views off screen and still allow interaction with your list. Here's what I've done...
On the main view
import SwiftUI
struct MainView: View {
#State private var isPresented = false
var body: some View {
NavigationView {
VStack {
//...
}
//Modal
.sheet(isPresented: $isPresented, content: {
AddItem(showModal: self.$isPresented)
})
}
}
}
The modal's view
import SwiftUI
struct AddItem: View {
#Binding var showModal: Bool
var body: some View {
VStack {
Button(action: {
self.showModal = false
}, label: {
Text("Cancel")
})
}
}
}