From 23bd1c7930aa58b7b8df3d73b737dccfe11dfefd Mon Sep 17 00:00:00 2001 From: EdisonJwa Date: Sat, 16 May 2026 18:23:57 +0800 Subject: [PATCH] fix(ui,ios): force TextInput.show on first tap (keyboard-up-on-first-tap) User reported: 'input field still need to click twice' on iPhone. The 020be77 Listener + requestFocus() approach was insufficient. Root cause analysis: * Flutter's EditableText opens the platform TextInput method channel (which is what slides the iOS soft keyboard up) only after a TapGestureRecognizer wins the gesture arena. * Our outer Listener calls node.requestFocus() pre-arena. That flags the FocusNode as focused in Flutter's focus tree, but does NOT open the TextInput channel \u2014 so iOS keeps the OS keyboard hidden until EditableText's own tap recognizer wins on a second tap. * requestFocus on its own is therefore a no-op for the user visually: the cursor + caret appear briefly but the keyboard stays down. Fix: in the Listener.onPointerDown handler, additionally invoke 'TextInput.show' on SystemChannels.textInput. This is the same private platform RPC EditableText calls internally on attach; forcing it ourselves slides the keyboard up regardless of arena state. Belt-and-braces with the existing requestFocus() guarantees keyboard-on-first-tap on iPhone / iPad and is harmless on: * Android (the platform ignores the redundant show call when the keyboard is already up), * Linux / Windows / macOS desktop (no soft keyboard exists; the method channel handler returns success without doing anything). No new imports needed \u2014 SystemChannels is already in package:flutter/services.dart (imported for FilteringTextInputFormatter). flutter build ios --release --no-codesign: 20.7 s, Runner.app 30.2 MB. --- apps/chanora_flutter/lib/main.dart | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/apps/chanora_flutter/lib/main.dart b/apps/chanora_flutter/lib/main.dart index 21b3c74..4eeb489 100644 --- a/apps/chanora_flutter/lib/main.dart +++ b/apps/chanora_flutter/lib/main.dart @@ -1267,12 +1267,38 @@ class _ConnectFormState extends State<_ConnectForm> { final FocusNode _passwordFocus = FocusNode(); Widget _focusOnTap(Widget child, FocusNode node) { + // iOS first-tap-not-focusing workaround. + // + // Symptom: the user taps a TextField the first time after the + // app launches (or after the field has not held focus this + // session); the cursor doesn't appear and the on-screen keyboard + // doesn't slide up. A second tap then works normally. + // + // Root cause: Flutter's EditableText opens the platform + // TextInput channel (which is what actually slides the iOS + // keyboard up) only after a TapGestureRecognizer **wins** the + // gesture arena. Our outer Listener (HitTestBehavior.translucent, + // onPointerDown) used to call node.requestFocus() pre-arena, + // which marks the node focused in Flutter's tree but does not + // open the TextInput channel \u2014 so the OS keyboard stays hidden + // until the EditableText's own tap recognizer wins on a second + // tap. + // + // Fix: in addition to requestFocus(), invoke 'TextInput.show' + // on the SystemChannels.textInput method channel. This is the + // same private RPC EditableText uses internally; calling it + // ourselves forces the OS keyboard up regardless of arena state. + // Belt-and-braces with the Listener guarantees keyboard-on-first- + // tap on iPhone / iPad and is harmless on Android (the platform + // ignores the redundant show call when the keyboard is already + // up) and on desktop (no soft keyboard exists). return Listener( behavior: HitTestBehavior.translucent, onPointerDown: (_) { if (!node.hasFocus) { node.requestFocus(); } + SystemChannels.textInput.invokeMethod('TextInput.show'); }, child: child, );