Search code examples
iosswiftuiscrollviewtextfieldios14

SwiftUI Textfield Padding when Keyboard is in view


I have a Scrollview with just textfields in it. I want to be able to tap on any textfield and have the keyboard push it up slightly.

struct DetailView: View {
    @EnvironmentObject var vm: ViewModel

    var body: some View {
        ScrollView {
            VStack {
                TextField("Enter stuff", text: $vm.username)
                    .padding(.bottom, 20)

                TextField("Enter stuff", text: $vm.username)
                    .padding(.bottom, 20)

                TextField("Enter stuff", text: $vm.username)
                    .padding(.bottom, 20)

                TextField("Enter stuff", text: $vm.username)
                    .padding(.bottom, 20)

                TextField("Enter stuff", text: $vm.username)
                    .padding(.bottom, 20)

                TextField("Enter stuff", text: $vm.username)
                    .padding(.bottom, 20)

                TextField("Enter stuff", text: $vm.username)
                    .padding(.bottom, 20)

                TextField("Enter stuff", text: $vm.username)
                    .padding(.bottom, 20)

                TextField("Enter stuff", text: $vm.username)
                    .padding(.bottom, 20)

                Group {
                    TextField("Enter stuff", text: $vm.username)
                        .padding(.bottom, 20)

                    TextField("Enter stuff", text: $vm.username)
                        .padding(.bottom, 20)

                    TextField("Enter stuff", text: $vm.username)
                        .padding(.bottom, 20)

                    TextField("Enter stuff", text: $vm.username)
                        .padding(.bottom, 20)

                    TextField("Enter stuff", text: $vm.username)
                        .padding(.bottom, 20)

                    TextField("Enter stuff", text: $vm.username)
                        .padding(.bottom, 20)

                    TextField("Enter stuff", text: $vm.username)
                        .padding(.bottom, 20)

                    TextField("Enter stuff", text: $vm.username)
                        .padding(.bottom, 20)

                    TextField("Enter stuff", text: $vm.username)
                        .padding(.bottom, 20)

                    TextField("Enter stuff", text: $vm.username)
                        .padding(.bottom, 20)
                }
            }
        }
    }
}

This works perfectly when there's no padding/styling in the textfield. If I use a custom textfield with styling (borders, padding), the keyboard hovers over part of the textfield. This is my custom textfield:

struct NotesField: View {
    @Binding var value: String

    init(_ value: Binding<String>) {
        self._value = value
    }

    var body: some View {
        TextField("Enter stuff", text: $value)
        .padding()
        .overlay(
            RoundedRectangle(cornerRadius: 10)
                .stroke(Color.gray, lineWidth: 1)
        )
    }
}

It's well known that ios14 handles this for you automatically so I want a solution where I don't have to use a view modifier to listen to when the keyboard is opened or not.


Solution

  • If you are using iOS 14+ with scrollview or have the option to use scrollview.

    https://developer.apple.com/documentation/swiftui/scrollviewproxy https://developer.apple.com/documentation/swiftui/scrollviewreader

    Below might help

        ScrollViewReader { (proxy: ScrollViewProxy) in
            ScrollView {
                view1().frame(height: 200)
                view2().frame(height: 200)
    
                view3() <-----this has textfields 
                    .onTapGesture {
                        proxy.scrollTo(1, anchor: .center)
                    }
                    .id(1)
    
                view4() <-----this has text editor
                    .onTapGesture {
                        proxy.scrollTo(2, anchor: .center)
                    }
                    .id(2)
    
                view5().frame(height: 200)
                view6().frame(height: 200)
                submtButton().frame(height: 200)
            }
        }
    

    imp part from above is

         anyView().onTapGesture {
              proxy.scrollTo(_ID, anchor: .center)
         }.id(_ID)
    

    Hope this helps someone :)