在 SwiftUI 中制作聊天应用程序:如何使 ScrollView 在键盘出现时保持其位置?

Arm*_*man 2 swiftui

我正在 SwiftUI 中制作一个聊天应用程序。这是我想要的效果:在 Telegram 或 Whatsapp 中打开任何聊天,点击输入框。当键盘向上滑动时,聊天内容也会向上滑动。因此,如果您正在查看底部消息,您仍然可以看到它。

我无法在 SwiftUI 中获得这种效果。键盘向上滑动不滑动聊天内容:

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()
    }
}
Run Code Online (Sandbox Code Playgroud)

有什么想法如何获得这种效果吗?

小智 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()
    }
}
Run Code Online (Sandbox Code Playgroud)