SwiftUI 相当于 UIViewController 的输入附件视图,即键盘上方的视图始终可见,就像在 iMessage 中一样

问题描述 投票:0回答:2

UIViewController 上的简单输入附件视图

我想要一个像 iMessage 中一样的输入附件视图。该栏始终在屏幕底部可见。当 TextField 获得焦点时,键盘会跳入,并且栏会自动向上移动,同时停留在键盘顶部。

即使没有 TextInput 具有焦点,输入附件也必须可见

在 UIKit 中,ViewController 可以覆盖 inputAccessory 并成为第一个 Responder。因此输入附件永久可见。我找不到在 SwiftUI 中执行此操作的方法。

键盘和配件必须缩小滚动视图

当键盘弹出时,保存消息并填充屏幕的滚动视图必须相应缩小。向下拖动滚动视图和交互移动键盘时也是如此。拖动时必须调整视图大小。

最重要的是:向下拖动滚动视图并交互移动键盘时必须起作用

最重要的要求是,当拖动然后滚动视图(以交互方式向下移动键盘)时,这必须顺利工作。 iMessage 或 WhatsApp 中的行为相同。输入附件必须在拖动时移动,并且滚动视图也必须调整大小。键盘关闭后,工具栏/输入附件必须在底部保持可见。

不重复

我读过InputAccessoryView / View Pinned to Keyboard with SwiftUI,但这与我的问题不相似。我需要工具栏可见,即使键盘未显示。此外,该问题中接受的答案在 iOS 15 中无法正常工作。拖动以关闭键盘会留下白色间隙。

UIKit 可以工作

在 UIKit 实现中,持有视图是一个带有键盘关闭交互集的 UITableViewController。这意味着,当显示键盘时,您可以拖动视图,并同时向下拖动键盘和附件视图,直到键盘消失。不过,附件视图仍然保留在底部。

在 UIKit 中实现非常简单,如下所示。一切都是开箱即用的。

class ChatTableViewController: UITableViewController {
...

    override var inputAccessoryView: UIView? {
        return inputBar
    }

    override var canBecomeFirstResponder: Bool {
        return true
    }
...
}

UIKit 实现看起来不错

需要 SwiftUI 帮助(Xcode 13 beta 5、iOS 15)

对于 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)
            }
        }
    }
}

但是如果没有焦点在 TextField 上,工具栏根本不可见

ios swift xcode swiftui inputaccessoryview
2个回答
2
投票

只要您的视图以某种方式锚定到视口的底部,当显示虚拟键盘时它就应该向上移动。例如,这里我使用

.overlay
修饰符来显示一个简单的视图,使用
VStack
Spacer()
来确保视图位于容器的底部:

NavigationView {
  EventForm()
    .overlay {
      VStack {
        Spacer()
        // replace the view below with your toolbar
        Text("Toolbar")
          .padding()
          .frame(maxWidth: .infinity)
          .background(Color.cyan)
      }
    }
}

Toolbar staying above keyboard

当键盘不存在时,视图将默认避开安全区域(注意彩色背景如何向下扩展)。

如果您想避免这种行为,则可以使用

.ignoresSafeArea
修饰符,但必须注意将键盘从要忽略的安全区域视图列表中排除。目前,唯一的安全区域值是
.container
.keyboard
,因此您可以明确:

.ignoresSafeArea(.container, edges: .bottom)

0
投票

尝试我的解决方案:https://github.com/frogcjn/BottomInputBarSwiftUI 它可以停靠在视图底部

© www.soinside.com 2019 - 2024. All rights reserved.