From b01d0bfd826536dce6b4f40d9ebfb69b5ea36377 Mon Sep 17 00:00:00 2001 From: "Andrei.Salavei" Date: Thu, 21 Dec 2023 18:07:45 +0100 Subject: [PATCH] Fix keyboard disappearing while switching between text fields --- .../platform/UIKitTextInputService.uikit.kt | 12 +++++++- .../compose/ui/window/FocusStack.uikit.kt | 28 ++++++++++++------- .../IntermediateTextInputUIView.uikit.kt.kt | 9 ++++++ 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/compose/ui/ui/src/uikitMain/kotlin/androidx/compose/ui/platform/UIKitTextInputService.uikit.kt b/compose/ui/ui/src/uikitMain/kotlin/androidx/compose/ui/platform/UIKitTextInputService.uikit.kt index c825f6da013b2..0107e6bba9b09 100644 --- a/compose/ui/ui/src/uikitMain/kotlin/androidx/compose/ui/platform/UIKitTextInputService.uikit.kt +++ b/compose/ui/ui/src/uikitMain/kotlin/androidx/compose/ui/platform/UIKitTextInputService.uikit.kt @@ -31,6 +31,8 @@ import org.jetbrains.skia.BreakIterator import org.jetbrains.skiko.SkikoKey import org.jetbrains.skiko.SkikoKeyboardEventKind import platform.UIKit.* +import platform.darwin.dispatch_async +import platform.darwin.dispatch_get_main_queue internal class UIKitTextInputService( private val updateView: () -> Unit, @@ -106,6 +108,7 @@ internal class UIKitTextInputService( currentImeOptions = imeOptions currentImeActionHandler = onImeActionPerformed + textUIView?.removeFromSuperview() textUIView = IntermediateTextInputUIView( keyboardEventHandler = keyboardEventHandler, ).also { @@ -127,7 +130,14 @@ internal class UIKitTextInputService( currentImeOptions = null currentImeActionHandler = null hideSoftwareKeyboard() - textUIView?.removeFromSuperview() + + textUIView?.input = null + textUIView?.let { view -> + + dispatch_async(dispatch_get_main_queue()) { + view.removeFromSuperview() + } + } textUIView = null } diff --git a/compose/ui/ui/src/uikitMain/kotlin/androidx/compose/ui/window/FocusStack.uikit.kt b/compose/ui/ui/src/uikitMain/kotlin/androidx/compose/ui/window/FocusStack.uikit.kt index ff1efcc5845fa..cff63aac76a06 100644 --- a/compose/ui/ui/src/uikitMain/kotlin/androidx/compose/ui/window/FocusStack.uikit.kt +++ b/compose/ui/ui/src/uikitMain/kotlin/androidx/compose/ui/window/FocusStack.uikit.kt @@ -18,6 +18,8 @@ package androidx.compose.ui.window import androidx.compose.ui.util.fastForEachReversed import platform.UIKit.UIView +import platform.darwin.dispatch_async +import platform.darwin.dispatch_get_main_queue /** * Stack to remember previously focused UIView. @@ -43,24 +45,30 @@ internal interface FocusStack { internal class FocusStackImpl : FocusStack { - private var list = emptyList() + private var activeViews = emptyList() + private var resignedViews = emptyList() override fun pushAndFocus(view: UIView) { - list += view + activeViews += view + resignedViews -= view view.becomeFirstResponder() } override fun popUntilNext(view: UIView) { - if (list.contains(view)) { - val index = list.indexOf(view) - list.subList(index, list.lastIndex).fastForEachReversed { - it.resignFirstResponder() + if (activeViews.contains(view)) { + val index = activeViews.indexOf(view) + resignedViews += activeViews.subList(index, activeViews.lastIndex) + activeViews = activeViews.subList(0, index) + + dispatch_async(dispatch_get_main_queue()) { + resignedViews.fastForEachReversed { + it.resignFirstResponder() + } + resignedViews = emptyList() + activeViews.lastOrNull()?.becomeFirstResponder() } - list = list.subList(0, index) - list.lastOrNull()?.becomeFirstResponder() } } - override fun first(): UIView? = list.firstOrNull() - + override fun first(): UIView? = activeViews.firstOrNull() } diff --git a/compose/ui/ui/src/uikitMain/kotlin/androidx/compose/ui/window/IntermediateTextInputUIView.uikit.kt.kt b/compose/ui/ui/src/uikitMain/kotlin/androidx/compose/ui/window/IntermediateTextInputUIView.uikit.kt.kt index 2ea535cbeb8b1..90cbd07038cbd 100644 --- a/compose/ui/ui/src/uikitMain/kotlin/androidx/compose/ui/window/IntermediateTextInputUIView.uikit.kt.kt +++ b/compose/ui/ui/src/uikitMain/kotlin/androidx/compose/ui/window/IntermediateTextInputUIView.uikit.kt.kt @@ -39,6 +39,7 @@ import platform.Foundation.NSSelectorFromString import platform.Foundation.dictionary import platform.UIKit.NSWritingDirection import platform.UIKit.NSWritingDirectionLeftToRight +import platform.UIKit.UIEvent import platform.UIKit.UIKeyInputProtocol import platform.UIKit.UIKeyboardAppearance import platform.UIKit.UIKeyboardType @@ -93,6 +94,14 @@ internal class IntermediateTextInputUIView( super.pressesEnded(presses, withEvent) } + override fun hitTest(point: CValue, withEvent: UIEvent?): UIView? { + return if (input == null) { + null + } else { + super.hitTest(point, withEvent) + } + } + /** * A Boolean value that indicates whether the text-entry object has any text. * https://developer.apple.com/documentation/uikit/uikeyinput/1614457-hastext