When a keyboard is proven, the presenting view will transfer backwards if the detent is taller than maxDetentValue - keyboardHeight
, so that you want a detent that could be a little bit shorter than that.
This implies you will have to someway cross the keyboard top right into a CustomPresentationDetent
implementation. I have not discovered a option to cross it via the context
parameter. The one different means I can consider is thru a synchronised international variable.
import Synchronization
struct CustomDetent: CustomPresentationDetent {
static let keyboardHeight: Mutex = .init(0)
static func top(in context: Context) -> CGFloat? {
keyboardHeight.withLock {
(context.maxDetentValue - $0) * 0.99
}
}
}
It is in all probability secure to make this a static nonisolated(unsafe) var
too if you might want to assist earlier variations. I extremely doubt top(for:)
will ever be known as from someplace apart from the principle actor, for the reason that corresponding UIKit API is fundamental actor remoted.
Use it like this:
.presentationDetents([.fraction(0.1), .fraction(0.333), .custom(CustomDetent.self)], choice: $selectedDetent)
.onChange(of: isSearchFocused) {_, targeted in
if targeted {
selectedDetent = .customized(CustomDetent.self)
}
}
You then arrange some publishers to watch the keyboard (from this reply):
extension Publishers {
static var keyboardHeight: AnyPublisher {
let willShow = NotificationCenter.default.writer(for: UIApplication.keyboardWillShowNotification)
.map { $0.keyboardHeight }
let willHide = NotificationCenter.default.writer(for: UIApplication.keyboardWillHideNotification)
.map { _ in CGFloat(0) }
return MergeMany(willShow, willHide)
.eraseToAnyPublisher()
}
}
extension Notification {
var keyboardHeight: CGFloat {
return (userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)?.top ?? 0
}
}
You possibly can put an onReceive
in your root view:
.onReceive(Publishers.keyboardHeight) { top in
CustomDetent.keyboardHeight.withLock { $0 = top }
}