在SwiftUI中创建聊天应用程序:如何在键盘显示时使ScrollView保持其位置?

时间:2020-10-10 02:52:32

标签: 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()
    }
}

任何想法如何获得这种效果?

1 个答案:

答案 0 :(得分:2)

您需要使用 Introspect 来获得对 UIScrollView 的访问权限并监听键盘高度的变化。

这是一个代码:

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()
    }
}