swiftui - 如何使底部按钮跟随 SwiftUI 中的键盘显示

标签 swiftui

在下面的帮助下,我能够跟随键盘显示上的按钮。 然而,动画不能很好地应用。

How to show complete List when keyboard is showing up in SwiftUI

import SwiftUI
import Combine
import UIKit

class KeyboardResponder: ObservableObject {
    let willset = PassthroughSubject<CGFloat, Never>()
    private var _center: NotificationCenter
    @Published var currentHeight: CGFloat = 0
    var keyboardDuration: TimeInterval = 0

    init(center: NotificationCenter = .default) {
        _center = center
        _center.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        _center.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
    }

    deinit {
        _center.removeObserver(self)
    }

    @objc func keyBoardWillShow(notification: Notification) {
        if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
            currentHeight = keyboardSize.height

            guard let duration:TimeInterval = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double else { return }
            keyboardDuration = duration
        }
    }

    @objc func keyBoardWillHide(notification: Notification) {
        currentHeight = 0
    }
}
import SwiftUI

struct Content: View {
    @ObservedObject var keyboard = KeyboardResponder()

    var body: some View {
        VStack {
            Text("text")

            Spacer()

            NavigationLink(destination: SubContentView()) {
                Text("Done")
            }
        }
        .padding(.bottom, keyboard.currentHeight)
        animation(Animation.easeInOut(duration: keyboard.keyboardDuration))
    }
}

enter image description here

最佳答案

您的主要问题是您使用的是隐式动画。不仅它可能会为您可能不想制作动画的东西制作动画,而且您永远不应该在容器上应用 .animation() 。在 SwiftUI 文档中的几个警告中,这是其中之一:

Use this modifier on leaf views rather than container views. The animation applies to all child views within this view; calling animation(_:) on a container view can lead to unbounded scope.

来源:https://developer.apple.com/documentation/swiftui/view/3278508-animation

修改后的代码删除了隐式的 .animation() 调用,并用两个隐式的 withAnimation 闭包替换了它。

我还用 keyboardFrameEndUserInfoKey 替换了 keyboardFrameEndUserInfoKey,第二次调用给出了无用的几何图形。

class KeyboardResponder: ObservableObject {
    let willset = PassthroughSubject<CGFloat, Never>()
    private var _center: NotificationCenter
    @Published var currentHeight: CGFloat = 0
    var keyboardDuration: TimeInterval = 0

    init(center: NotificationCenter = .default) {
        _center = center
        _center.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        _center.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
    }

    deinit {
        _center.removeObserver(self)
    }

    @objc func keyBoardWillShow(notification: Notification) {
        if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {

            guard let duration:TimeInterval = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double else { return }
            keyboardDuration = duration

            withAnimation(.easeInOut(duration: duration)) {
                self.currentHeight = keyboardSize.height
            }

        }
    }

    @objc func keyBoardWillHide(notification: Notification) {
        guard let duration:TimeInterval = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double else { return }

        withAnimation(.easeInOut(duration: duration)) {
            currentHeight = 0
        }
    }
}


struct ContentView: View {
    @ObservedObject var keyboard = KeyboardResponder()

    var body: some View {

        return VStack {
            Text("text \(keyboard.currentHeight)")

            TextField("Enter text", text: .constant(""))
            Spacer()

            NavigationLink(destination: Text("SubContentView()")) {
                Text("Done")
            }
        }
        .padding(.bottom, keyboard.currentHeight)
//        .animation(Animation.easeInOut(duration: keyboard.keyboardDuration))
    }
}

关于swiftui - 如何使底部按钮跟随 SwiftUI 中的键盘显示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57739966/

相关文章:

swift - API滥用: Attempt to serialize store access on non-owning coordinator - with Assets. xcassets

macos - SwiftUI 按钮可点击外部图像吗?

swiftui - 如何在 SwiftUI 中创建单选按钮?

ios - SwiftUI 无法在 iOS 13 版本中使用 navigationBarTitle 修饰符(已弃用),但可以在 iOS 14 中使用

swift - 按下键盘后面的按钮时应用程序崩溃

ios - SwifUI 激活 ForEach 中的所有可用索引

ios - 如何在 SwiftUI 中的两个 View 模型之间共享已发布的模型?

swift - 如何在 SwiftUI WidgetKit 占位符中自定义占位符外观?

ios - SwiftUI Charts BarMark 将注释与图表顶部对齐

ios - 自定义选择器可以访问选项值,而不仅仅是选定的索引