Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scroll up to see TextField when the keyboard appears in SwiftUI

In my use case, I have to put a TextField below the available items in a List and by using that TextField, we can add items to the List.

Initially, there're no list items (items array is empty)

Here's a minimal, reproducible example

import SwiftUI

struct ContentView: View {
    @State var itemName = ""
    @State var items = [String]()

    var body: some View {
        NavigationView {
            List {
                ForEach(self.items, id: \.self) {
                    Text($0)
                }

                VStack {
                    TextField("Item Name", text: $itemName)
                        .textFieldStyle(RoundedBorderTextFieldStyle())

                    Button(action: {
                        self.items.append(self.itemName)
                        self.itemName = ""

                    }) {
                        Text("Add Item")
                    }
                }
            }
        .navigationBarTitle(Text("Title"))
        }
    }
}

We can add a new item to the list by typing something in the TextField and clicking "Add Item" Button , Every item that we add using TextField appears above the TextField in the List. So the TextField goes down in the List (Just like Apple’s Reminders app).

If the app has many items (more than 7 items), the keyboard covers the TextField when the keyboard appears and we can’t see the TextField.
Check this screenshot:

What I want to know is how to automatically scroll the List (move the view up) to see the TextField when keyboard appears (like in Apple's Reminders app).

like image 618
umayanga Avatar asked Sep 17 '19 13:09

umayanga


People also ask

How do I move view up when keyboard appears in iOS SwiftUI?

Moving SwiftUI View Up When Keyboard Appears Create keyboard height state. SwiftUI will automatically update the view whenever the keyboard height changes. Add padding to the bottom of the view, which will make it move up and down with the keyboard.

How do I know if my SwiftUI keyboard is visible?

Using this protocol, KeyboardReadable , you can conform to any View and get keyboard updates from it. It works by using Combine and creating a publisher so we can receive the keyboard notifications. You can now read from the isKeyboardVisible variable to know if the keyboard is visible.

How do I make the keyboard disappear in SwiftUI?

Pure SwiftUI (iOS 15) To dismiss the keyboard, simply set view's focusedField to nil . The return key will dismiss keyboard automatically (since iOS 14).


1 Answers

I had a similar problem in my recent project, the easiest way for me to solve it was to wrap UITextField in SwiftUI and from my custom wrapper reach to the parent scroll view and tell it to scroll when the keyboard appears. I tried my approach on your project and it seems to work.

If you take my code for the wrapper and other files from this GitHub folder: https://github.com/LostMoa/SwiftUI-Code-Examples/tree/master/ScrollTextFieldIntoVisibleRange and then replace the SwiftUI TextField with my custom view (TextFieldWithKeyboardObserver) then it should scroll.

import SwiftUI

struct ContentView: View {
    @State var itemName = ""
    @State var items = [String]()

    var body: some View {
        NavigationView {
            List {
                ForEach(self.items, id: \.self) {
                    Text($0)
                }

                VStack {
                    TextFieldWithKeyboardObserver(text: $itemName, placeholder: "Item Name")

                    Button(action: {
                        self.items.append(self.itemName)
                        self.itemName = ""

                    }) {
                        Text("Add Item")
                    }
                }
            }
        .navigationBarTitle(Text("Title"))
        }
    }
}

I recently wrote an article explaining this solution: https://lostmoa.com/blog/ScrollTextFieldIntoVisibleRange/

like image 68
Natalia Panferova Avatar answered Oct 22 '22 20:10

Natalia Panferova