2

I am making a chat app in SwiftUI. Here is the effect that I want to have: open any chat in Telegram or Whatsapp, tap on the input box. The content of the chat slides up when the keyboard slides up. So if you were looking at say the bottom message, you can still see it.

I am unable to get this effect in SwiftUI. Keyboard sliding up does not slide the content of the chat:

import SwiftUI

struct SlidingKeyboardTest: View {
    @State var inputText = "Placeholder"
    
    var body: some View {
        VStack {
            ScrollView {
                LazyVStack {
                    ForEach(1...100, id: \.self) { id in
                        HStack {
                            Spacer()
                            Text("message \(id)")
                            Spacer()
                        }
                    }
                }
            }
            TextEditor(text: $inputText)
                .frame(height: 50)
        }
        .background(LinearGradient(gradient: Gradient(colors: [.white, .blue, .white]), startPoint: .top, endPoint: .bottom))
        .onTapGesture { UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) }
    }
}

struct SlidingKeyboardTest_Previews: PreviewProvider {
    static var previews: some View {
        SlidingKeyboardTest()
    }
}

Any ideas how to get this effect?

Arman
  • 1,208
  • 1
  • 12
  • 17

1 Answers1

5

You need to use Introspect to receive access to UIScrollView and listen to keyboard height changes.

Here is a code:

import Combine
import Introspect
import SwiftUI

struct SlidingKeyboardTest: View {
    @State var inputText = "Placeholder"
    @State var keyboardHeight = CGFloat(0)
    @State var scrollView: UIScrollView? = nil

    var body: some View {
        VStack {
            ScrollView {
                LazyVStack {
                    ForEach(1 ... 100, id: \.self) { id in
                        HStack {
                            Spacer()
                            Text("message \(id)")
                            Spacer()
                        }
                    }
                }
            }.introspectScrollView {
                scrollView = $0
            }
            TextEditor(text: $inputText)
                .frame(height: 50)
        }.onReceive(Publishers.keyboardHeight) { height in
            if height > 0 {
                self.scrollView!.setContentOffset(CGPoint(x: 0, y: self.scrollView!.contentOffset.y + height), animated: true)
            } else {
                self.scrollView!.contentOffset.y = max(self.scrollView!.contentOffset.y - keyboardHeight, 0)
            }

            keyboardHeight = height
        }

        .background(LinearGradient(gradient: Gradient(colors: [.white, .blue, .white]), startPoint: .top, endPoint: .bottom))
        .onTapGesture { UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) }
    }
}

struct SlidingKeyboardTest_Previews: PreviewProvider {
    static var previews: some View {
        SlidingKeyboardTest()
    }
}
Yakir Zana
  • 51
  • 1
  • 4