How to Drag down to dismiss a view in Swiftui - swiftui

I created a view similar to the code I attached. It uses offset and a boolean to toggle the view up and down with either a button or a tap on outside space. HOWEVER, I been trying to also dismiss by dragging down. I tried many ways but apparently don't know enough about gestures to figure it out. I tried copying code from others but it hasn't worked out. I'd like it to behave the way Instagram's hamburger menu works in the users view. I attached some gifs of how mine works and how instagrams works.
enter image description here
enter image description here
struct View1: View {
#EnvironmentObject var viewModel : ViewModel
var body: some View {
ZStack {
VStack {
Text("Press Me")
Spacer()
}.padding(.top,50)
.onTapGesture {
withAnimation(.default) {
viewModel.offsetView.toggle()
}
}
} //Z
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
.overlay(
View2()
)
}
}
struct View2: View {
#EnvironmentObject var viewModel : ViewModel
let array = ["ITEM 1", "ITEM 2", "ITEM 3", "ITEM 4", "ITEM 5", "ITEM 6"]
let screenH = UIScreen.main.bounds.height
let screenW = UIScreen.main.bounds.width
var body: some View {
VStack {
ForEach (self.array, id: \.self) { array in
Text(array)
.padding(.vertical)
Divider()
}
Spacer()
} //V
.background(.bar)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
.offset(y: viewModel.offsetView ? screenH/2.2:screenH)
.environmentObject(ViewModel())
}
}
struct View1_Previews: PreviewProvider {
static var previews: some View {
View1()
.environmentObject(ViewModel())
}
}
class ViewModel: ObservableObject {
#Published var offsetView = false
}

Related

How to move a view with the keyboard while attached similar to .toolbar

I want to have the TextEditor1 to be on the bottom of the app, then when user taps on the TextEditor1 to type the message, the TextEditor1 should attached to the keyboard and move up with it. I used the following code, it attaches to it through the .toolbar, but don't know how to make TextEditor1 stay in the bottom of the app etc and then move up with the keyboard. Image is attached for further clarification.
import SwiftUI
struct ContentView: View {
#State var textTyped: String = "this is textttt"
var body: some View {
TextEditor (text: $textTyped)
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
TextEditor1()
}
}
.frame(height: 200, alignment: .leading)
.padding(.horizontal, 10)
}
}
struct TextEditor1: View {
#State var textTyped: String = "this is textttt"
var body: some View {
TextEditor (text: $textTyped)
.frame(height: 200, alignment: .leading)
.padding(.horizontal, 10)
}
}
Is this what you want? I also put a colored .background() on to see the outlines of the TextEditor. I find it helps to be able to visualize the extent of the views.
struct ContentView: View {
#State var textTyped: String = "this is textttt"
var body: some View {
VStack {
Spacer()
TextEditor (text: $textTyped)
.frame(height: 200, alignment: .leading)
// .padding(.horizontal, 10)
.padding()
.background(Color.yellow.opacity(0.2))
}
}
}

How to change the background based on focused item in a ForEach

I'm using a ForEach within a horizontal ScrollView to display a list of movies from my movies array. I want to make an interaction like Netflix where the background updates with the an image, movie description, etc. based on the item currently in focus.
This is the best solution I've managed to come up with so far but its very far off.
My MainMenuView:
struct MainMenuView: View {
#ObservedObject var vm = MainMenuViewModel()
var body: some View {
VStack {
Text("Movies")
.font(.title3.weight(.semibold))
.frame(maxWidth: .infinity, alignment: .leading)
ScrollView(.horizontal) {
LazyHStack {
ForEach(vm.selections) { selection in
Button {
print("Hello, World!")
} label: {
ZStack {
SelectionPreview(selection: selection)
.frame(maxWidth: UIScreen.main.bounds.width, maxHeight: UIScreen.main.bounds.height, alignment: .bottom)
Image(selection.thumbnail)
.resizable()
.scaledToFill()
.frame(width: 500, height: 281)
}
}
.cornerRadius(32)
.buttonStyle(.plain)
}
}
}
}
}
}
My SelectionPreview:
struct SelectionPreview: View {
#State var selection: Movie
#Environment(\.isFocused) var isFocused: Bool
var body: some View {
Image(isFocused ? selection.backdrop : "")
.resizable()
.aspectRatio(contentMode: .fit)
}
}
The above code does manage to update a background based on the current item in focus but all the other items in the list get pushed to the side since the View is now the size of the background image.
I also tried to set a background on the entire VStack instead but this didn't work. I think because the Vstack on its own is not focusable:
Something like this:
struct MainMenuView: View {
var body: some View {
VStack {
ScrollView(.horizontal) {
[...]
}
}
.background(
SelectionPreview()
)
}
}
My goal is to achieve something similar to this:
Any help would be appreciated!

iOS 15 SwiftUI Conditionals on a view with Navigation View makes NavigationBar config to be ignore if navigationViewStyle stack

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)
}
}

Keyboard not overlaying the view in SwiftUI

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))

SwiftUI do not push navigation with keyboard with Xcode 12

I made a simple app to illustrate the issue. I have a custom Tab view, however when I click on text field and open the keyboard and my navigation tabs is being pushed up as well. I would like for navigation to be not visible (as one would expect for any app).
This image illustrates the problem:
This issue does not happen if I use native TabView, however I would like to use custom tabs. Does anyone figured out how to deal with it? Providing the code below.
struct ContentView: View {
#State var menu = 0
var body: some View {
VStack {
VStack {
if menu == 0 {
FirstPage()
} else if menu == 1 {
Text("all is good")
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
CustomTabs(menu: $menu)
}
}
}
struct CustomTabs: View {
#Binding var menu: Int
var body: some View {
HStack {
Spacer()
Text("Nav1")
.onTapGesture{
self.menu = 0
}
Spacer()
Text("Nav2")
.onTapGesture{
self.menu = 1
}
Spacer()
}
.padding()
.background(Color(.red))
}
}
struct FirstPage: View {
#State var mood: String = ""
var body: some View {
VStack {
Text("How are you?")
TextField("answer textfield", text: $mood)
}
}
}
A possible solution/work-around would be to embed the CustomTabs in a VStack with a Spacer which pushes the tabs down even when the keyboard appears and then put this Stack in front of your view via ZStack.
struct ContentView: View {
#State var menu = 0
var body: some View {
ZStack {
VStack {
if menu == 0 {
FirstPage()
} else if menu == 1 {
Text("all is good")
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
VStack {
Spacer(minLength: UIScreen.main.bounds.height - 70)
CustomTabs(menu: $menu)
.frame(height: 70)
}
}
}
}
For simplicity I just decided to set the tabs height to 70. A more beautiful solution would be to use GeometryReader.