调整键盘出现/消失的视图:动画曲线问题
Posted
技术标签:
【中文标题】调整键盘出现/消失的视图:动画曲线问题【英文标题】:Adjusting a view for keyboard appearing/disappearing: problem with animation curve 【发布时间】:2020-04-04 01:32:32 【问题描述】:我正在尝试创建一个 SwiftUI 视图修改器,它添加底部填充以响应屏幕键盘的出现或消失。这是我正在使用的方法:
struct KeyboardAdjustingModifier: ViewModifier
@ObservedObject private var responder = KeyboardResponder()
func body(content: Content) -> some View
GeometryReader proxy in
content
.padding(.bottom, self.bottomPadding(in: proxy))
func bottomPadding(in proxy: GeometryProxy) -> CGFloat
if responder.endFrame == .zero
return 0
else
return max(0, proxy.frame(in: .global).maxY - self.responder.endFrame.minY)
fileprivate final class KeyboardResponder: ObservableObject
@Published var endFrame: CGRect = .zero
init(notificationCenter: NotificationCenter = .default)
notificationCenter.addObserver(self,
selector: #selector(keyboardWillShowOrChangeFrame(notification:)),
name: UIResponder.keyboardWillShowNotification, object: nil)
notificationCenter.addObserver(self,
selector: #selector(keyboardWillShowOrChangeFrame(notification:)),
name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
notificationCenter.addObserver(self,
selector: #selector(keyboardWillHide(notification:)),
name: UIResponder.keyboardWillHideNotification, object: nil)
@objc private func keyboardWillShowOrChangeFrame(notification: Notification)
withAnimation(Animation(curve: notification.animationCurve, duration: notification.duration))
endFrame = notification.endFrame
@objc private func keyboardWillHide(notification: Notification)
withAnimation(Animation(curve: notification.animationCurve, duration: notification.duration))
endFrame = .zero
struct Info
let curve: UIView.AnimationCurve
let duration: TimeInterval
let endFrame: CGRect
fileprivate extension Animation
init(curve: UIView.AnimationCurve, duration: TimeInterval)
switch curve
case .easeInOut:
self = .easeInOut(duration: duration)
case .easeIn:
self = .easeIn(duration: duration)
case .easeOut:
self = .easeOut(duration: duration)
case .linear:
self = .linear(duration: duration)
@unknown default:
self = .easeInOut(duration: duration)
fileprivate extension Notification
var animationCurve: UIView.AnimationCurve
guard let rawValue = (userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int) else
return UIView.AnimationCurve.linear
return UIView.AnimationCurve(rawValue: rawValue)!
var duration: TimeInterval
userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval ?? 0
var endFrame: CGRect
userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect ?? .zero
我遇到的问题是 SwiftUI 动画曲线似乎与键盘的动画曲线完全不同:
有谁知道是否可以像这样将 SwiftUI 动画与 UIKit 同步?我将通知的 userInfo
中的动画曲线信息映射到 SwiftUI 动画曲线的方式很可能存在错误。还是我应该考虑另一种解决这个问题的方法?
我尝试的另一件事是使用UIHostingController
直接在 UIKit 中处理动画。它与键盘正确同步,但如果 SwiftUI 也在同时为内容制作动画,我在我的动画块中调用 layoutIfNeeded
时遇到了崩溃。
【问题讨论】:
【参考方案1】:这是我正在使用的,它几乎可以完美运行:
演示
代码
public extension View
func adaptToKeyboard() -> some View
modifier(AdaptToSoftwareKeyboard())
public struct AdaptToSoftwareKeyboard: ViewModifier
@State var currentHeight: CGFloat = 0
public func body(content: Content) -> some View
content
.padding(.bottom, currentHeight)
.edgesIgnoringSafeArea(.bottom)
.animation(.spring())
.onAppear(perform: subscribeToKeyboardEvents)
private func subscribeToKeyboardEvents()
NotificationCenter.Publisher(
center: NotificationCenter.default,
name: UIResponder.keyboardWillShowNotification
)
.compactMap $0.userInfo?["UIKeyboardFrameEndUserInfoKey"] as? CGRect
.map $0.height
.subscribe(Subscribers.Assign(object: self, keyPath: \.currentHeight))
NotificationCenter.Publisher(
center: NotificationCenter.default,
name: UIResponder.keyboardWillHideNotification
)
.compactMap _ in CGFloat.zero
.subscribe(Subscribers.Assign(object: self, keyPath: \.currentHeight))
用法
someView()
.adaptToKeyboard()
在此处使用演示进行测试:https://github.com/youjinp/SwiftUIKit
【讨论】:
以上是关于调整键盘出现/消失的视图:动画曲线问题的主要内容,如果未能解决你的问题,请参考以下文章
如何更改自定义 UICollectionView 布局引擎中的默认布局动画曲线?