Beware of ZStacks and Keyboard avoidance
This week I found a really annoying bug in my new app, Job Finder Tracker. That I was convinced I had caused, but could not figure out how or why it was happening.
This screenshot says it all.
So let me explain what is happening here.
The Problem
I have a SwiftUI view with a ZStack wrapped around the content, along with a navigation stack.
The first item in the stack is the background image that sits nicely until the keyboard appears after you tap the first two fields in the form. Then, the content is pushed up by the keyboard and the fields are now behind the navigation bar.
This is not the behavior I expect.
I carefully reviewed and experimented with the modifiers and display order to find where I had made the mistake. But, nothing I tried or removed, fixed it.
Then as a last resort, I removed the image from the top of the ZStack. Everything started working right, the fields no longer went behind the navigation when the keyboard appeared.
I was confused, and continued to experiment to understand why.
At the end of it, I cannot explain why other than a theory. That being, the image for the background scales for device sizes, that means no constant numbers. And this is throwing off the screen rendering somehow when the keyboard appears and the view is recalculated incorrectly, pushing the content up.
The Solution
Knowing this, I also knew a way to fix the problem. I attached the background image in a different way to the view content. Instead of adding it as an object to display, I changed it to the background property of the scrollview. Here is the sample code.
ScrollView {
…
}
.background {
Image("Background2") // Asset name
.resizable()
.aspectRatio(contentMode: .fill)
.edgesIgnoringSafeArea(.all)
}
There is still a side effect, the background image I use has a design that you can still see move up when the keyboard appears/disappears. But, this actually adds a nice subtle animation to the view that compliments rather than hurts it.
So, if you are experiencing unexpected results from keyboards and entry fields, and, you have a ZStack. You might want to explore this idea to see if it helps you.