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.
This commit is contained in:
@@ -1267,12 +1267,38 @@ class _ConnectFormState extends State<_ConnectForm> {
|
|||||||
final FocusNode _passwordFocus = FocusNode();
|
final FocusNode _passwordFocus = FocusNode();
|
||||||
|
|
||||||
Widget _focusOnTap(Widget child, FocusNode node) {
|
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(
|
return Listener(
|
||||||
behavior: HitTestBehavior.translucent,
|
behavior: HitTestBehavior.translucent,
|
||||||
onPointerDown: (_) {
|
onPointerDown: (_) {
|
||||||
if (!node.hasFocus) {
|
if (!node.hasFocus) {
|
||||||
node.requestFocus();
|
node.requestFocus();
|
||||||
}
|
}
|
||||||
|
SystemChannels.textInput.invokeMethod<void>('TextInput.show');
|
||||||
},
|
},
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user