Timmerz
Timmerz

Reputation: 6199

SwiftUI ScrollView Keyboard Avoidance

First off. I know the SwiftUI ScrollView has limitations. I am hoping to get around that here.

My problem is I have a chat box...so a VStack with a ScrollView and a text input. I am able to get the text input to be keyboard adaptive...i.e. when you type it shifts up with the keyboard.

The issue is that the ScrollView loses its scroll position. So, if you scroll to the bottom and then activate the keyboard...you can't see the bottom anymore. It's almost like a ZStack.

What I want is to mimic the same behavior as WhatsApp which maintains scroll position while typing a new message.

I know about the ScrollViewReader and scrollTo...that seems to be a hack in this case and I'm hoping to avoid it. If anything, maybe there is a layout related fix?

Upvotes: 5

Views: 8326

Answers (2)

Abhishek
Abhishek

Reputation: 494

Maybe a better option. 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 :)

Upvotes: 2

Timmerz
Timmerz

Reputation: 6199

By a stroke of luck I was able to solve this by adding .keyboardAdaptive() to both the ScrollView and the text input as well as changing from padding to offset

struct KeyboardAdaptive: ViewModifier {
    @State private var keyboardHeight: CGFloat = 0

    @State var offset: CGFloat
    
    func body(content: Content) -> some View {
        content
            .offset(y: -keyboardHeight)
            .onReceive(Publishers.keyboardHeight) {
                self.keyboardHeight = $0 == 0 ? 0 : $0 - offset
            }
    }
}

Upvotes: 3

Related Questions