SwiftUI ScrollView extra padding when go to another screen with showed keyboard - ios

The default "Keyboard Avoidance" SwiftUI is used.
First GIF
If you put the code in VStack and add another View to it, then the container rises
Second GIF
I don't want to delete Keyboard Avoidance. I need to remove extra spacing
scrollDismissesKeyboard for ScrollView is not an option
minimal iOS version is iOS 16
struct ContentView: View {
#State var text: String = "Bu bu?"
var body: some View {
NavigationStack {
ScrollViewReader { proxy in
VStack {
ScrollView(showsIndicators: false) {
VStack(spacing: 0) {
Spacer()
.frame(height: 500)
TextField("", text: $text)
.padding(.bottom, 70)
.frame(height: 40)
.frame(maxWidth: .infinity)
.background(Color.red)
NavigationLink("Screen 2", destination: {
Text("SwiftUI - Nice to meet you, let's never meet again")
})
}
}
Text("I'm in VSTack after scroll view")
}
}
}
}
}
I looked it up with a hierarchy view, and noticed that a UIInputSetHostView is created with a height of 216
View hierarchy 1
View hierarchy 2
disableAutocorrection not working

Related

Extraneous alignment of a SwiftUI.Menu when animated by the keyboard appearing

I'm facing a weird alignment issue with a floating menu when the keyboard appears and I've no idea if there's a workaround. To reproduce the issue, simply copy and paste this code:
struct ContentView: View {
#State var searchQuery = ""
var customToolbarButton: some View {
VStack {
Text("Example").font(.footnote)
Image(systemName: "arrowtriangle.down.fill").imageScale(.small)
}.foregroundColor(.accentColor)
}
var body: some View {
NavigationView {
Rectangle().fill(.red)
.safeAreaInset(edge: .bottom) {
HStack(alignment: .center) {
customToolbarButton
Spacer()
Menu { } label: {
customToolbarButton
}
}
.frame(height: 52)
.padding(.horizontal)
.background(Color.white)
.clipShape(Capsule(style: .continuous))
}
}.searchable(text: $searchQuery)
}
}
When the keyboard appears and moves the HStack up, the views that are a Menu are wrongly placed, all other views seem fine. Any idea if there's a fix?
Video to illustrate the issue: https://twitter.com/xmollv/status/1616851571832229889

Removing initial space from ScrollView in swift UI

I'm having trouble with the initial position of a Scroll View in my iOS app:there's a toolbar and my scroll view is wrapped inside the NavigationView.I would like to remove the spacing between "Testo 1" and the top navigation bar.I've searched on the internet but I've only found something about ScrollViewReader,but actually I need to remove the space when the view loads. Is it possible to remove that space?
In the first image you'll see what happen when I open the app, then what appears when I scroll down
That's my code:
import SwiftUI
struct ProvaScrollView: View {
var body: some View {
NavigationView(){
ScrollView{
Text("Testo 1")
VStack{
CardView(title: "Title", text: "Card Text", colore:.blue)
Spacer(minLength: 10)
Title(testo: "Titolo 2")
Spacer(minLength: 3)
Text("Descrizione ")
.multilineTextAlignment(.center)
dishImage()
}}
.padding().toolbar(){
ToolbarItem(placement:.navigation){
NavigationLink(destination: ListOfRecipes()){
Text("Back")
}
}
ToolbarItem(placement:.principal){
Text("Prova Scroll View")
.font(.system(size: 20))
.fontWeight(.black)
}
}
.ignoresSafeArea(.all, edges: .bottom)
}.navigationBarBackButtonHidden()
}
}
Thanks in advance

SwiftUI onTapGuesture not working using offset inside ZStack?

I have a Mapbox map view and a search bar and activate button (HStack) inside a ZStack and using an offset modifier to position them at the top of the screen.
For some reason the offset is preventing the onTapGesture from working for the activate button, if I comment out the offset it will work but will be placed at the bottom of the screen.
I tried adding the offset to each element individually inside the HStack but that did not work...
How can I make the onTapGesture functionality work with offset?
Thank you
struct MapScreen: View {
var body: some View {
NavigationView {
ZStack(alignment: .bottom) {
HStack(spacing: 10) {
SearchBar()
.padding(.leading, 5)
.onTapGesture {
print("search pressed")
}
ActivateButton()
.onTapGesture {
print("activate pressed")
}
}.zIndex(2)
.offset(y: -770)
MapView(locations: $locations)
.edgesIgnoringSafeArea([.top, .bottom])
BottomNavBar().zIndex(1)
.edgesIgnoringSafeArea(.all).offset(y: 35)
}
.navigationViewStyle(StackNavigationViewStyle())
.fullScreenCover(isPresented: $presentSearchView, content: {
SearchView()
})
}
}
}
There's a couple problems here:
.offset(y: -770)
If you're trying to use an offset so large, you shouldn't be using offset at all. offset is usually for fine-tune adjustments and doesn't work great with big values. And also, 770 is hardcoded. What happens when you use another device with a different screen size? Don't hardcode or do calculations yourself — SwiftUI can do it for you!
Instead, use a VStack + Spacer() to push the search bar up.
ZStack(alignment: .bottom) {
VStack { /// here!
HStack(spacing: 10) {
SearchBar()
.padding(.leading, 5)
.onTapGesture {
print("search pressed")
}
ActivateButton()
.onTapGesture {
print("activate pressed")
}
}
Spacer() /// push the `HStack` to the top of the screen
}
.zIndex(2)
MapView(locations: $locations)
.edgesIgnoringSafeArea([.top, .bottom])
BottomNavBar().zIndex(1)
.edgesIgnoringSafeArea(.all).offset(y: 35)
}

Place text between top and center of the screen

Is there a simple way to place text relatively between the top and center of the screen? With 'simple' I mean preferably without GeometryReader and overt calculations.
I've tried various combinations of VStack, Zstack and Spacer() but to no avail.
Code and screenshot as illustration:
struct ContentView: View {
var body: some View {
Text("Between top and center")
.offset(y: -150)
Text("Center")
}
}
A possible solution is to create two views on each side of the centred text (one hidden):
struct ContentView: View {
var body: some View {
VStack {
Spacer()
Text("Between top and center")
Spacer()
Text("Center")
Spacer()
Text("")
Spacer()
}
}
}
Alternatively, to be fool-proof (in case they change the behaviour of Text("") in the future release):
struct ContentView: View {
var body: some View {
VStack {
Spacer()
Text("Between top and center")
Spacer()
Text("Center")
Spacer()
Text("Between top and center")
.opacity(0)
Spacer()
}
}
}
(If needed, Text("Between top and center") can be extracted as a subview to avoid code duplication.)
As you said:
Spacer() [...] ensure[s] that the empty spaces between the views are equal in size
That's exactly the reason why I recommended to extract Text("Between top and center") as a subview. Then, you can change the font, size etc. of the view in one place only.
The adapted solution is:
struct ContentView: View {
var body: some View {
ZStack {
VStack {
Spacer()
subview
Spacer()
Spacer()
subview
.opacity(0)
Spacer()
}
VStack {
Spacer()
Text("Center")
Spacer()
}
}
}
var subview: some View {
Text("Between top and center")
.font(.caption)
// apply all other modifiers if you want
}
}
Here is possible solution (tested with Xcode 12.1 / iOS 14.1)
struct ContentView: View {
var body: some View {
VStack {
Color.clear.overlay(
Text("Between top and center") // << here !!
)
// Text("Between top and center")
// .frame(maxWidth: .infinity, maxHeight: .infinity) // alternate !!
Text("Center")
Color.clear
}
}
}
Update: added alternate with .frame but it is valid only if there should be the only one Text, whereas in .overlay it is possible to put anything.
Here is another solution using the method of VStack Spacers, I also used a little padding to get you closer to the center.
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Text("Top").bold()
.foregroundColor(.blue)
Spacer()
Text("Your desired area")
Spacer()
Text("Middle Text").bold()
.foregroundColor(.blue)
.padding(.bottom, 200)
Spacer()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

Present Modal fullscreem SwiftUI

how can i present a modal that will take up the fullscreen and can't be dismissed by swiping it down? Currently I am using .sheet on a view to present a modal that is dismissible.
I haven't noticed any beta changes in Xcode that changes this behavior.
Any help would be appreciated :)
SwiftUI 1.0
I'm not sure if this what you'd want to go with but it's possible to create your own modal screen by using the ZStack and a state variable to control the hiding/showing of it.
Code
struct CustomModalPopups: View {
#State private var showingModal = false
var body: some View {
ZStack {
VStack(spacing: 20) {
Text("Custom Popup").font(.largeTitle)
Text("Introduction").font(.title).foregroundColor(.gray)
Text("You can create your own modal popup with the use of a ZStack and a State variable.")
.frame(maxWidth: .infinity)
.padding().font(.title).layoutPriority(1)
.background(Color.orange).foregroundColor(Color.white)
Button(action: {
self.showingModal = true
}) {
Text("Show popup")
}
Spacer()
}
// The Custom Popup is on top of the screen
if $showingModal.wrappedValue {
// But it will not show unless this variable is true
ZStack {
Color.black.opacity(0.4)
.edgesIgnoringSafeArea(.vertical)
// This VStack is the popup
VStack(spacing: 20) {
Text("Popup")
.bold().padding()
.frame(maxWidth: .infinity)
.background(Color.orange)
.foregroundColor(Color.white)
Spacer()
Button(action: {
self.showingModal = false
}) {
Text("Close")
}.padding()
}
.frame(width: 300, height: 200)
.background(Color.white)
.cornerRadius(20).shadow(radius: 20)
}
}
}
}
}
Example
(Excerpt from "SwiftUI Views" book)
So here, your popup is small, but you can adjust the dimensions to make it fullscreen with the frame modifier that is on that VStack.

Resources