15
votes

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)")
        }
    }
}
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. - Duncan C
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. - DaWiseguy

4 Answers

17
votes

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

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

6
votes

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.

0
votes

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.