24

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)")
        }
    }
}
Malav Soni
  • 2,739
  • 1
  • 23
  • 52
  • 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 Sep 18 '20 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. – DaWiseguy Nov 03 '21 at 21:40

6 Answers6

37

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)
    }
}
pawello2222
  • 46,897
  • 22
  • 145
  • 209
19

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

Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278
  • 8
    The modifier simply doesn't work. The TextField is still moved upwards.. :( – los.adrian Sep 19 '20 at 15:51
  • Maybe you missed the original code implementation. I. have added a full code demo to make it reproducible for you ;) – Mojtaba Hosseini Oct 25 '20 at 11:18
  • 1
    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 – JAHelia Mar 25 '21 at 10:40
  • You can apply to parent vstack also. it's working for me .ignoresSafeArea(.keyboard, edges: .bottom) – Shrikant Phadke Jul 11 '22 at 09:56
9

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.

Gabb
  • 187
  • 2
  • 5
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.

los.adrian
  • 509
  • 1
  • 6
  • 19
  • 1
    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? – Jonathan Dudley Aug 06 '23 at 16:14
3

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.

Latynskii
  • 53
  • 6
  • I confirm. Putting `GeometryReader` just beneath `NavigationView` did resolve the thing for me. I did not even have to use `ignoresSafeArea` – optimista May 20 '23 at 04:32
-1

anyway fixed size Views will always jump up. the only solution for me was to use ScrollView instead of VStack

dem.nz
  • 24
  • 4