umayanga
umayanga

Reputation: 2764

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

Upvotes: 19

Views: 10016

Answers (1)

Natalia Panferova
Natalia Panferova

Reputation: 1184

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/

Upvotes: 7

Related Questions