8.3 C
New York
Sunday, March 16, 2025

ios – Forestall scaling of background view in SwiftUI when .sheet will get introduced by @FocusState


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 }
}

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles