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

Posted

技术标签:

【中文标题】如何使底部按钮跟随 SwiftUI 中的键盘显示【英文标题】:How to make the bottom button follow the keyboard display in SwiftUI 【发布时间】:2019-08-31 16:52:26 【问题描述】:

在以下内容的帮助下,我能够按照键盘显示屏上的按钮进行操作。 但是动画不能很好的应用。

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

【问题讨论】:

那么,具体您的问题是什么?不得不承认,“但是,动画不能很好的应用”是比较模糊的。 我想用与键盘从下方显示的相同动画(持续时间、延迟、缓动等)从下到上移动按钮。 【参考方案1】:

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

在叶视图而不是容器视图上使用此修饰符。这 动画适用于该视图内的所有子视图;打电话 容器视图上的动画(_:) 可能导致无限范围。

来源: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))
    

【讨论】:

谢谢!我修复了it,但是按钮移动比键盘慢。 我对曲线进行了硬编码,也许你也应该得到那个值(keyboardAnimationCurveUserInfoKey:developer.apple.com/documentation/uikit/… 非常好! :+1: @kontiki keyboardAnimationCurveUserInfoKey 的值为 7。显然,他们使用未记录的曲线进行键盘动画。我们可以用原始值 7 初始化未记录的UIView.AnimationCurve 值,但该曲线只能用于UIKit,不能用于SwiftUI。除非我遗漏了什么,否则目前无法在SwiftUI 中正确跟随键盘动画。

以上是关于如何使底部按钮跟随 SwiftUI 中的键盘显示的主要内容,如果未能解决你的问题,请参考以下文章

如果它不可见,SwiftUI 如何使 NavigationLink 工作?

导航栏中的 SwiftUI 元素不响应状态

在 SwiftUI 中显示键盘上方的视图 [关闭]

如何使视图与键盘对齐

如何使底栏随键盘向上移动(颤动)

如何使按钮宽度跟随基于文本的最大宽度按钮?