30

I am using TextField in my view and when it becomes the first responder, it lefts the view as shown in the below GIF.

Is there any way I can get rid of this behavior?

enter image description here

Here is my code

NavigationView(content: {
    ZStack{
        MyTabView(selectedIndex: self.$index)
            .view(item: self.item1) {
                NewView(title: "Hello1").navigationBarTitle("")
                    .navigationBarHidden(true)
            }
            .view(item: self.item2) {
                NewView(title: "Hello2").navigationBarTitle("")
                    .navigationBarHidden(true)
            }
            .view(item: self.item3) {
                NewView(title: "Hello3").navigationBarTitle("")
                    .navigationBarHidden(true)
            }
    }.navigationBarHidden(true)
    .navigationBarTitle("")
}).ignoresSafeArea(.keyboard, edges: .bottom)

// New View

struct NewView:View {
    @State var text:String = ""
    var title:String
    var body: some View {
        VStack {
            Spacer()
            Text("Hello")
            TextField(title, text: self.$text)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            
        }.padding()
        .onAppear {
            debugPrint("OnApper \(self.title)")
        }
    }
}
2
  • 4
    Why would you want to get rid of that behavior? If you don't raise the text field it gets covered by the keyboard and you can't tell what you are typing, OR use tap/drag gestures to change the selection. It makes editing unusable. Commented Sep 18, 2020 at 16:49
  • Because in iOS13 the keyboard simply goes over automatically.. as expected. Once again we are having to add our if statements for ios14. And I'm sure there will be more if statements for ios15. Commented Nov 3, 2021 at 21:40

5 Answers 5

46

For .ignoresSafeArea to work you need to fill all the available area (eg. by using a Spacer).


The following will not work (no Spacers, just a TextField):

struct ContentView: View {
    @State var text: String = ""
    var body: some View {
        VStack {
            TextField("asd", text: self.$text)
                .textFieldStyle(RoundedBorderTextFieldStyle())
        }
        .ignoresSafeArea(.keyboard, edges: .bottom)
    }
}

However, it will work when you add Spacers (fill all the available space):

struct ContentView: View {
    @State var text: String = ""
    var body: some View {
        VStack {
            Spacer()
            TextField("asd", text: self.$text)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            Spacer()
        }
        .ignoresSafeArea(.keyboard, edges: .bottom)
    }
}

If you don't want to use Spacers you can also use a GeometryReader:

struct ContentView: View {
    @State var text: String = ""
    var body: some View {
        GeometryReader { _ in
            ...
        }
        .ignoresSafeArea(.keyboard, edges: .bottom)
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

all it doesnt work if you have this modifer. (.edgesIgnoringSafeArea(.all))
22

You should apply the modifier on the ZStack, NOT the NavigationView

NavigationView(content: {
    ZStack{
        ,,,
    }.navigationBarHidden(true)
    .navigationBarTitle("")
    .ignoresSafeArea(.keyboard, edges: .bottom) // <- This line moved up
})

Full working example:

struct ContentView: View {
    @State var text = ""
    var body: some View {
        VStack{
            Spacer()
            Text("Hello, World")
            TextField("Tap to test keyboard ignoring", text: $text)
                .textFieldStyle(RoundedBorderTextFieldStyle())
        }
        .padding()
        .ignoresSafeArea(.keyboard, edges: .bottom)
    }
}

Demo

4 Comments

The modifier simply doesn't work. The TextField is still moved upwards.. :(
Maybe you missed the original code implementation. I. have added a full code demo to make it reproducible for you ;)
if I have some rows included in the view like this: ScrollView { LazyVStack { Rows ... } } using ignoresSafeArea will cause flickering in the rows which is obvious and annoying
You can apply to parent vstack also. it's working for me .ignoresSafeArea(.keyboard, edges: .bottom)
12

What eventually worked for me, combining answers posted here and considering also this question, is the following (Xcode 12.4, iOS 14.4):

GeometryReader { _ in
    VStack {
        Spacer()
        TextField("Type something...", text: $value)
        Spacer()
    }.ignoresSafeArea(.keyboard, edges: .bottom)
}

Both spacers are there to center vertically the textfield.

Using only the GeometryReader or the ignoresSafeArea modifier didn't do the trick, but after putting them all together as shown above stopped eventually the view from moving up upon keyboard appearance.

2 Comments

I had a custom video player with a fixed size that kept lifting up out of screen, and this worked perfect!
YES. This was what was needed => both GeometryReader and .ignoresSafeArea. So aggravating
7

I had case when i used NavigationView and Stacks inside it, and there was couple of local "content" views. I had the same trouble like did the author had. My solution - GeometryReader but very important - inside of NavigationView! Code below:

NavigationView {
        GeometryReader { _ in
            VStack {
                // below VStacks
                textFieldsGroup
                buttonsGroup
                socialEnterGroup
                    .padding(.top, 40)
                Spacer()
            }
            .padding(.top, 20)
            .navigationTitle("Enter")
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .padding()
            .ignoresSafeArea(.keyboard, edges: .bottom)
        }
    }

I hope this helps someone.

1 Comment

I confirm. Putting GeometryReader just beneath NavigationView did resolve the thing for me. I did not even have to use ignoresSafeArea
6

That's what I figured out:

GeometryReader { _ in
    ZStack {
        //PUT CONTENT HERE
    }.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
}

It seems to work for me. In this case you do not need to check iOS 14 availability.

1 Comment

This worked for me - but the other answers did not. Does anyone know why this is necessary - perhaps if the ZStack is the root element in the view?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.