Malav Soni
Malav Soni

Reputation: 2838

iOS 14 SwiftUI Keyboard lifts view automatically

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)")
        }
    }
}

Upvotes: 30

Views: 29622

Answers (5)

Latynskii
Latynskii

Reputation: 93

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.

Upvotes: 6

pawello2222
pawello2222

Reputation: 54426

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

Upvotes: 45

Gabb
Gabb

Reputation: 307

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.

Upvotes: 11

Mojtaba Hosseini
Mojtaba Hosseini

Reputation: 119148

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

Upvotes: 20

los.adrian
los.adrian

Reputation: 538

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.

Upvotes: 6

Related Questions