我想要一个像 iMessage 中一样的输入附件视图。该栏始终在屏幕底部可见。当 TextField 获得焦点时,键盘会跳入,并且栏会自动向上移动,同时停留在键盘顶部。
在 UIKit 中,ViewController 可以覆盖 inputAccessory 并成为第一个 Responder。因此输入附件永久可见。我找不到在 SwiftUI 中执行此操作的方法。
当键盘弹出时,保存消息并填充屏幕的滚动视图必须相应缩小。向下拖动滚动视图和交互移动键盘时也是如此。拖动时必须调整视图大小。
最重要的要求是,当拖动然后滚动视图(以交互方式向下移动键盘)时,这必须顺利工作。 iMessage 或 WhatsApp 中的行为相同。输入附件必须在拖动时移动,并且滚动视图也必须调整大小。键盘关闭后,工具栏/输入附件必须在底部保持可见。
我读过InputAccessoryView / View Pinned to Keyboard with SwiftUI,但这与我的问题不相似。我需要工具栏可见,即使键盘未显示。此外,该问题中接受的答案在 iOS 15 中无法正常工作。拖动以关闭键盘会留下白色间隙。
在 UIKit 实现中,持有视图是一个带有键盘关闭交互集的 UITableViewController。这意味着,当显示键盘时,您可以拖动视图,并同时向下拖动键盘和附件视图,直到键盘消失。不过,附件视图仍然保留在底部。
在 UIKit 中实现非常简单,如下所示。一切都是开箱即用的。
class ChatTableViewController: UITableViewController {
...
override var inputAccessoryView: UIView? {
return inputBar
}
override var canBecomeFirstResponder: Bool {
return true
}
...
}
对于 SwiftUI,我已经发现在 iOS 15 中有一个 placement: .keyboard 参数,它允许将工具栏放在键盘顶部。问题是,这只有在 TextField 获得焦点时才有效。如果没有文本字段获得焦点,即键盘不可见或关闭,则工具栏不可见。
struct Chat: View {
@State private var text: String = ""
var body: some View {
ZStack {
ScrollView {
ScrollViewReader { value in
LazyVStack(spacing: 15) {
ForEach((1...10), id: \.self) { x in
let isOwner = x % 2 == 0;
ChatMessage(isOwner: isOwner)
.padding(.leading, isOwner ? 90 : 0)
.padding(.trailing, isOwner ? 0 : 90)
}
}
.padding(.horizontal)
.padding(.top, 10)
.onAppear {
value.scrollTo(10, anchor: .bottomTrailing)
}
}
}
.background(Color.red)
.ignoresSafeArea(.keyboard)
VStack {
// Toolbar only visible if this box has focus
TextField("", text: $text)
.padding(10)
.background(Color(.systemGray6))
.cornerRadius(5)
}
}
.navigationBarTitle("test")
.navigationBarTitleDisplayMode(.inline)
.onAppear {
UIScrollView.appearance().keyboardDismissMode = .interactive
}
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
HStack {
TextField("", text: $text)
.padding(10)
.background(Color(.systemGray6))
.cornerRadius(5)
Text("Hello")
}
.padding(.vertical, 5)
.padding(.horizontal)
.background(Color.blue)
}
}
}
}
只要您的视图以某种方式锚定到视口的底部,当显示虚拟键盘时它就应该向上移动。例如,这里我使用
.overlay
修饰符来显示一个简单的视图,使用 VStack
和 Spacer()
来确保视图位于容器的底部:
NavigationView {
EventForm()
.overlay {
VStack {
Spacer()
// replace the view below with your toolbar
Text("Toolbar")
.padding()
.frame(maxWidth: .infinity)
.background(Color.cyan)
}
}
}
当键盘不存在时,视图将默认避开安全区域(注意彩色背景如何向下扩展)。
如果您想避免这种行为,则可以使用
.ignoresSafeArea
修饰符,但必须注意将键盘从要忽略的安全区域视图列表中排除。目前,唯一的安全区域值是 .container
和 .keyboard
,因此您可以明确:
.ignoresSafeArea(.container, edges: .bottom)
尝试我的解决方案:https://github.com/frogcjn/BottomInputBarSwiftUI 它可以停靠在视图底部