我想知道在按下按钮时键盘是否存在。我该怎么做?我已经尝试过了,但没有成功。谢谢。
使用这个协议,KeyboardReadable
,你可以符合任何View
并从中获取键盘更新。
KeyboardReadable
协议:
KeyboardReadable
协议:
import Combine
import UIKit
/// Publisher to read keyboard changes.
protocol KeyboardReadable {
var keyboardPublisher: AnyPublisher<Bool, Never> { get }
}
extension KeyboardReadable {
var keyboardPublisher: AnyPublisher<Bool, Never> {
Publishers.Merge(
NotificationCenter.default
.publisher(for: UIResponder.keyboardWillShowNotification)
.map { _ in true },
NotificationCenter.default
.publisher(for: UIResponder.keyboardWillHideNotification)
.map { _ in false }
)
.eraseToAnyPublisher()
}
}
它通过使用Combine并创建一个发布者,以便我们可以接收键盘通知来实现。
以下是一个应用示例:
struct ContentView: View, KeyboardReadable {
@State private var text: String = ""
@State private var isKeyboardVisible = false
var body: some View {
TextField("Text", text: $text)
.onReceive(keyboardPublisher) { newIsKeyboardVisible in
print("Is keyboard visible? ", newIsKeyboardVisible)
isKeyboardVisible = newIsKeyboardVisible
}
}
}
现在你可以阅读 isKeyboardVisible
变量以确定键盘是否可见。
当 TextField
激活并显示键盘时,会打印以下内容:
键盘是否可见?true
当按下回车键隐藏键盘后,将打印以下内容:
键盘是否可见?false
您可以使用 keyboardWillShowNotification
/keyboardWillHideNotification
来在键盘开始出现或消失时进行更新,以及 keyboardDidShowNotification
/keyboardDidHideNotification
变体来在键盘已经出现或消失后更新。我更喜欢使用 will
变体,因为当键盘显示时更新是即时的。
我对George的回答进行了一点改进。
在View协议内部实现发布者权限。
import Combine
extension View {
var keyboardPublisher: AnyPublisher<Bool, Never> {
Publishers
.Merge(
NotificationCenter
.default
.publisher(for: UIResponder.keyboardWillShowNotification)
.map { _ in true },
NotificationCenter
.default
.publisher(for: UIResponder.keyboardWillHideNotification)
.map { _ in false })
.debounce(for: .seconds(0.1), scheduler: RunLoop.main)
.eraseToAnyPublisher()
}
}
我还添加了防抖操作符,以防止在您有多个文本字段并且用户在它们之间移动时进行真 - 假切换。
在任何视图中使用
struct SwiftUIView: View {
@State var isKeyboardPresented = false
@State var firstTextField = ""
@State var secondTextField = ""
var body: some View {
VStack {
TextField("First textField", text: $firstTextField)
TextField("Second textField", text: $secondTextField)
}
.onReceive(keyboardPublisher) { value in
isKeyboardPresented = value
}
}
}
您可以使用focused(_:)
视图修饰符和@FocusState
属性包装器来判断一个文本字段是否正在编辑,并改变其编辑状态。
@State private var text: String = ""
@FocusState private var isTextFieldFocused: Bool
var body: some View {
VStack {
TextField("hello", text: $text)
.focused($isTextFieldFocused)
if isTextFieldFocused {
Button("Keyboard is up!") {
isTextFieldFocused = false
}
}
}
}
使用环境密钥...
借鉴@Lepidopteron的答案,但使用它来驱动环境密钥。
这使您可以在任何视图中访问键盘状态
@Environment(\.keyboardShowing) var keyboardShowing
RootView()
.addKeyboardVisibilityToEnvironment()
这一切都由以下的ViewModifier文件驱动...
public extension View {
/// Sets an environment value for keyboardShowing
/// Access this in any child view with
/// @Environment(\.keyboardShowing) var keyboardShowing
func addKeyboardVisibilityToEnvironment() -> some View {
modifier(KeyboardVisibility())
}
}
private struct KeyboardShowingEnvironmentKey: EnvironmentKey {
static let defaultValue: Bool = false
}
extension EnvironmentValues {
var keyboardShowing: Bool {
get { self[KeyboardShowingEnvironmentKey.self] }
set { self[KeyboardShowingEnvironmentKey.self] = newValue }
}
}
private struct KeyboardVisibility:ViewModifier {
#if os(macOS)
fileprivate func body(content: Content) -> some View {
content
.environment(\.keyboardShowing, false)
}
#else
@State var isKeyboardShowing:Bool = false
private var keyboardPublisher: AnyPublisher<Bool, Never> {
Publishers
.Merge(
NotificationCenter
.default
.publisher(for: UIResponder.keyboardWillShowNotification)
.map { _ in true },
NotificationCenter
.default
.publisher(for: UIResponder.keyboardWillHideNotification)
.map { _ in false })
.debounce(for: .seconds(0.1), scheduler: RunLoop.main)
.eraseToAnyPublisher()
}
fileprivate func body(content: Content) -> some View {
content
.environment(\.keyboardShowing, isKeyboardShowing)
.onReceive(keyboardPublisher) { value in
isKeyboardShowing = value
}
}
#endif
}
import SwiftUI
和import Combine
。我在初始的WindowGroup
中的第一个调用ContentView()
中添加了.addKeyboardVisibilityToEnvironment()
,并在我的ContentView
视图顶部添加了@Environment(\.keyboardShowing) var keyboardShowing
。一切都运行得很完美。再次感谢。 - SPMstruct OnkeyboardAppearHandler: ViewModifier {
var handler: (Bool) -> Void
func body(content: Content) -> some View {
content
.onAppear {
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { _ in
handler(true)
}
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { _ in
handler(false)
}
}
}
}
extension View {
public func onKeyboardAppear(handler: @escaping (Bool) -> Void) -> some View {
modifier(OnkeyboardAppearHandler(handler: handler))
}
}
will
变体,因为更新是即时的,而did
变体需要等待整个出现/消失动画。 - George