top of page
  • Writer's pictureJennifer Eve Vega

SwiftUI: TextField and Keyboard Management

Just like everyone, I still encounter simple issues like the keyboard covering my textfield. We may have solutions for UIKit like listening for keyboard events, and manually moving our views (or if you're using a TableView, it has a different solution, too). But we don't want to use the same solution on SwiftUI. I mean, you can, but if you want to get rid of UIKit in your project, we should also start fixing some issues in a SwiftUI-y way.


Some may actually have the UIKit solution wrapped in SwiftUI Modifiers, but I still didn't want to use that. Because in the end, I'll still be using UIKit. Actually, I don't want to use it with the mentality that "as long as it works, it's good."


So how do we actually fix the keyboard covering our textfields in a SwiftUI way?

We simply need to add this to make the view move up when there is a keyboard:

.ignoresSafeArea(.container)

If you have this modifier, you might also need to remove this:

.edgesIgnoringSafeArea 

as it is hindering the ignoresSafeArea from working properly. Remove it from any of the view (or parent container view) with the textField. This will move the screen up even though you did not tap to focus on the textField yet. And since this keyboard management actually moves the entire view up, if you have this modifier, you'll have an empty screen at the bottom without the keyboard - and it looks ugly.


What if it still doesn't work and the keyboard is still covering my textField?

Sometimes, we have complicated views/subviews and simply doing what we did above might not work. We might want to try and make sure that our view with the textField has a space to move up to.


What does it mean to make sure our view has a space to move up to?


For example, you have this view above. At a glance, you'll think about using a VStack for the top (Image) and bottom (LoginForm) views.

@ViewBuilder
private var loginFormView: some View {
    VStack(.spacing: 8) {
        title
        HStack(.spacing: 8) {
            description
            image
        }
        textField
    }
}

var body: some View {
    VStack {
        Image

        loginFormView
          .padding(.horizontal, 8)
    }
    .ignoresSafeArea(.container)
}

These are just code snippets and this example is just for demonstration purposes.


As you notice, the textfield is at the bottom, so we want to be able to see the textfield move up when it's active so that it will not be covered by the keyboard. But with our sample code above, you'll know that our textField's view has no place to move up to. There is an image at the top, and the bottom (LoginForm) view is also full with other UI elements.


What I would do is create a ZStack and put 2 VStacks with Spacers at the bottom/top to put the views in their right place.

@ViewBuilder
private var loginFormView: some View {
    title
    HStack(.spacing: 8) {
        description
        image
    }
    textField
}

var body: some View {
    ZStack {
        VStack(.spacing: 8) {
            Image
            Spacer()
        }
        
        VStack(.spacing: 8) {
            Spacer()
            loginFormView
        }
        .padding(.horizontal, 8)
    }
    .ignoresSafeArea(.container)
}

The Spacer() in the VStack where our loginFormView is, is what it'll need to be able to move up. The loginFormView which has the textField in it can move up because the top part of the VStack is empty.

Comments


bottom of page