Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Programmatically select text in unfocused textfield not working #96339

Closed
imaachman opened this issue Jan 8, 2022 · 12 comments
Closed

Programmatically select text in unfocused textfield not working #96339

imaachman opened this issue Jan 8, 2022 · 12 comments
Labels
a: text input Entering text in a text field or keyboard related problems c: regression It was better in the past than it is now f: focus Focus traversal, gaining or losing focus f: material design flutter/packages/flutter/material repository. found in release: 2.8 Found to occur in 2.8 found in release: 2.9 Found to occur in 2.9 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on

Comments

@imaachman
Copy link

imaachman commented Jan 8, 2022

Steps to Reproduce

  1. Execute flutter run on the code sample or run it in DartPad.
  2. Tap floating action button to select the entire text in text field, programmatically.
  3. Tap the button on right of text field to focus on text field.

Expected results:
Selection UI should appear even when text field is not focused. This restriction wasn't there in earlier versions of Flutter and has been added recently.

Actual results:
Selection UI appears only when text field has focus.

Code sample
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late final TextEditingController controller;
  late final FocusNode focusNode;

  @override
  void initState() {
    super.initState();

    focusNode = FocusNode(debugLabel: 'TextField FocusNode');
    controller = TextEditingController();
    controller.text = 'Select this text';
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
          child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          SizedBox(
            width: 200,
            child: TextField(
              focusNode: focusNode,
              controller: controller,
            ),
          ),
          const SizedBox(width: 16),
          IconButton(
            tooltip: 'Focus text field',
            onPressed: () => focusNode.requestFocus(),
            icon: const Icon(Icons.center_focus_strong),
          )
        ],
      )),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          controller.selection = controller.selection
              .copyWith(baseOffset: 0, extentOffset: controller.text.length);
        },
        tooltip: 'Select text',
        child: const Icon(Icons.select_all_rounded),
      ),
    );
  }

  @override
  void dispose() {
    focusNode.dispose();
    controller.dispose();
    super.dispose();
  }
}
Logs

flutter run --verbose

[  +66 ms] executing: [C:\src\flutter\flutter/] git -c log.showSignature=false log -n 1 --pretty=format:%H
[ +474 ms] Exit code 0 from: git -c log.showSignature=false log -n 1 --pretty=format:%H
[   +2 ms] 77d935af4db863f6abd0b9c31c7e6df2a13de57b
[   +1 ms] executing: [C:\src\flutter\flutter/] git tag --points-at 77d935af4db863f6abd0b9c31c7e6df2a13de57b
[  +59 ms] Exit code 0 from: git tag --points-at 77d935af4db863f6abd0b9c31c7e6df2a13de57b
[        ] 2.8.1
[   +8 ms] executing: [C:\src\flutter\flutter/] git rev-parse --abbrev-ref --symbolic @{u}
[  +33 ms] Exit code 0 from: git rev-parse --abbrev-ref --symbolic @{u}
[        ] origin/stable
[        ] executing: [C:\src\flutter\flutter/] git ls-remote --get-url origin
[  +30 ms] Exit code 0 from: git ls-remote --get-url origin
[        ] https://github.com/flutter/flutter.git
[ +102 ms] executing: [C:\src\flutter\flutter/] git rev-parse --abbrev-ref HEAD
[  +33 ms] Exit code 0 from: git rev-parse --abbrev-ref HEAD
[        ] stable
[  +86 ms] Artifact Instance of 'AndroidGenSnapshotArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'AndroidInternalBuildArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'IOSEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterWebSdk' is not required, skipping update.
[   +4 ms] Artifact Instance of 'WindowsEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'WindowsUwpEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerDebugSymbols' is not required, skipping update.
[ +110 ms] Artifact Instance of 'AndroidGenSnapshotArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'AndroidInternalBuildArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'IOSEngineArtifacts' is not required, skipping update.
[   +3 ms] Artifact Instance of 'WindowsEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'WindowsUwpEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxEngineArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'LinuxFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'MacOSFuchsiaSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerSDKArtifacts' is not required, skipping update.
[        ] Artifact Instance of 'FlutterRunnerDebugSymbols' is not required, skipping update.
[  +85 ms] Skipping pub get: version match.
[ +118 ms] Generating C:\Users\imaac\Desktop\Codelessly\Flutter Issues\bug\android\app\src\main\java\io\flutter\plugins\GeneratedPluginRegistrant.java
[ +131 ms] Launching lib\main.dart on Chrome in debug mode...
[ +111 ms] Updating assets
[  +79 ms] Waiting for connection from debug service on Chrome...
[ +113 ms] <- reset
[  +12 ms] C:\src\flutter\flutter\bin\cache\dart-sdk\bin\dart.exe --disable-dart-dev C:\src\flutter\flutter\bin\cache\artifacts\engine\windows-x64\frontend_server.dart.snapshot --sdk-root
C:\src\flutter\flutter\bin\cache\flutter_web_sdk/ --incremental --target=dartdevc --debugger-module-names --experimental-emit-debug-metadata -DFLUTTER_WEB_AUTO_DETECT=true --output-dill
C:\Users\imaac\AppData\Local\Temp\flutter_tools.46ac3dcf\flutter_tool.6a3bcce2\app.dill --libraries-spec file:///C:/src/flutter/flutter/bin/cache/flutter_web_sdk/libraries.json --packages
C:\Users\imaac\Desktop\Codelessly\Flutter Issues\bug\.dart_tool\package_config.json -Ddart.vm.profile=false -Ddart.vm.product=false --enable-asserts --track-widget-creation --filesystem-root
C:\Users\imaac\AppData\Local\Temp\flutter_tools.46ac3dcf\flutter_tools.cd6b3fba --filesystem-scheme org-dartlang-app --initialize-from-dill build\b1b715402d823b7fd5c2b68d2edcb2ce.cache.dill.track.dill --platform
file:///C:/src/flutter/flutter/bin/cache/flutter_web_sdk/kernel/flutter_ddc_sdk_sound.dill --sound-null-safety
[  +15 ms] <- compile org-dartlang-app:/web_entrypoint.dart
[+17806 ms] Waiting for connection from debug service on Chrome... (completed in 17.9s)
[   +1 ms] Synced 28.4MB.
[        ] <- accept
[        ] Caching compiled dill
[ +508 ms] [CHROME]:
[   +1 ms] [CHROME]:DevTools listening on ws://127.0.0.1:60713/devtools/browser/164fcb5b-0ebb-4874-bea2-dbbac73b49a5
[ +616 ms] DwdsInjector: Received request for entrypoint at http://localhost:60691/main_module.bootstrap.js
[   +5 ms] MetadataProvider: Loading debug metadata...
[  +15 ms] MetadataProvider: Loaded debug metadata (sound null safety)
[   +8 ms] DwdsInjector: Injected debugging metadata for entrypoint at http://localhost:60691/main_module.bootstrap.js
[+2780 ms] ChromeProxyService: Initializing expression compiler for main_module.bootstrap.js with sound null safety: true
[  +99 ms] DevHandler: Debug service listening on ws://127.0.0.1:60738/QLdJTWn6Dk8=/ws

[  +24 ms] This app is linked to the debug service: ws://127.0.0.1:60738/QLdJTWn6Dk8=/ws
[  +12 ms] Debug service listening on ws://127.0.0.1:60738/QLdJTWn6Dk8=/ws
[   +1 ms]  Running with sound null safety 
[   +4 ms]   To hot restart changes while running, press "r" or "R".
[   +1 ms] For a more detailed help message, press "h". To quit, press "q".
[   +2 ms] An Observatory debugger and profiler on Chrome is available at: http://127.0.0.1:60738/QLdJTWn6Dk8=
[+2767 ms] The Flutter DevTools debugger and profiler on Chrome is available at: http://127.0.0.1:9102?uri=http://127.0.0.1:60738/QLdJTWn6Dk8=

flutter analyze

Analyzing bug...                                                        
No issues found! (ran in 2.5s)

flutter doctor -v

[√] Flutter (Channel stable, 2.8.1, on Microsoft Windows [Version 10.0.22000.376], locale en-IN)
    • Flutter version 2.8.1 at C:\src\flutter\flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 77d935af4d (3 weeks ago), 2021-12-16 08:37:33 -0800
    • Engine revision 890a5fca2e
    • Dart version 2.15.1

[!] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    • Android SDK at C:\Users\imaac\AppData\Local\Android\sdk
    X cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.
    X Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/windows#android-setup for more details.

[√] Chrome - develop for the web
    • Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe

[√] Visual Studio - develop for Windows (Visual Studio Community 2019 16.8.4)
    • Visual Studio at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community
    • Visual Studio Community 2019 version 16.8.30907.101
    • Windows 10 SDK version 10.0.18362.0

[√] Android Studio (version 4.1)
    • Android Studio at C:\Program Files\Android\Android Studio
    • Flutter plugin can be installed from:
       https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
       https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)

[√] VS Code (version 1.63.2)
    • VS Code at C:\Users\imaac\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.29.0

[√] Connected device (3 available)
    • Windows (desktop) • windows • windows-x64    • Microsoft Windows [Version 10.0.22000.376]
    • Chrome (web)      • chrome  • web-javascript • Google Chrome 96.0.4664.110
    • Edge (web)        • edge    • web-javascript • Microsoft Edge 95.0.1020.40

! Doctor found issues in 1 category.

Video Demo

Link to video: https://www.loom.com/share/60e3a165a06e42ee84890a32d6fbc9f6

@BirjuVachhani
Copy link

+1

@rayliverified
Copy link

This recent change breaks our text editor capabilities.
For a text editor, if you highlight a portion of text and try to apply a style to that selected text via a button (bold, italic, font), the focus shifts to the button or font selection drop down.
We want to restore the user text selection after their selection but it does not display because of this new limitation.

@maheshmnj maheshmnj added the in triage Presently being triaged by the triage team label Jan 10, 2022
@maheshmnj
Copy link
Member

maheshmnj commented Jan 10, 2022

Hi @imaachman, Thanks for filing the issue. I am able to reproduce the issue on stable and the master channel and It is working fine on stable 2.5.3. This indeed seems like a regression.

Code sample in the original post

stable 2.8 / master 2.9 stable 2.5.3
Screen.Recording.2022-01-10.at.2.27.54.PM.mov
Screen.Recording.2022-01-10.at.2.46.22.PM.mov
flutter doctor -v
[✓] Flutter (Channel master, 2.9.0-1.0.pre.298, on macOS 12.1 21C52 darwin-arm, locale en-GB)
    • Flutter version 2.9.0-1.0.pre.298 at /Users/mahesh/Documents/flutter_master
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 8ee8d0f6a8 (38 minutes ago), 2022-01-10 03:40:21 -0500
    • Engine revision 1e45f5cb6c
    • Dart version 2.16.0 (build 2.16.0-144.0.dev)
    • DevTools version 2.9.2

[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
    • Android SDK at /Users/mahesh/Library/Android/sdk
    • Platform android-31, build-tools 31.0.0
    • ANDROID_HOME = /Users/mahesh/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 13.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.10.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)

[✓] IntelliJ IDEA Community Edition (version 2021.2.1)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 60.1.4
    • Dart plugin version 212.5080.8

[✓] VS Code (version 1.63.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.32.0

[✓] Connected device (3 available)
    • iPhone 12 Pro (mobile) • B622CBB7-F906-4FA7-8F49-FACEAAC905AB • ios            • com.apple.CoreSimulator.SimRuntime.iOS-14-5 (simulator)
    • macOS (desktop)        • macos                                • darwin-arm64   • macOS 12.1 21C52 darwin-arm
    • Chrome (web)           • chrome                               • web-javascript • Google Chrome 96.0.4664.110

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!
[✓] Flutter (Channel stable, 2.8.1, on macOS 12.1 21C52 darwin-arm, locale en-GB)
    • Flutter version 2.8.1 at /Users/mahesh/Documents/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 77d935af4d (4 weeks ago), 2021-12-16 08:37:33 -0800
    • Engine revision 890a5fca2e
    • Dart version 2.15.1

⡿y[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
    • Android SDK at /Users/mahesh/Library/Android/sdk
    • Platform android-31, build-tools 31.0.0
    • ANDROID_HOME = /Users/mahesh/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 13.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.10.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)

[✓] IntelliJ IDEA Community Edition (version 2021.2.1)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 60.1.4
    • Dart plugin version 212.5080.8

[✓] VS Code (version 1.63.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.32.0

[✓] Connected device (3 available)
    • iPhone 12 Pro (mobile) • B622CBB7-F906-4FA7-8F49-FACEAAC905AB • ios            • com.apple.CoreSimulator.SimRuntime.iOS-14-5 (simulator)
    • macOS (desktop)        • macos                                • darwin-arm64   • macOS 12.1 21C52 darwin-arm
    • Chrome (web)           • chrome                               • web-javascript • Google Chrome 96.0.4664.110

• No issues found!
[✓] Flutter (Channel stable, 2.5.3, on macOS 12.1 21C52 darwin-arm, locale en-GB)
    • Flutter version 2.5.3 at /Users/mahesh/Documents/flutter_beta
    • Upstream repository unknown
    • Framework revision 18116933e7 (3 months ago), 2021-10-15 10:46:35 -0700
    • Engine revision d3ea636dc5
    • Dart version 2.14.4

[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
    • Android SDK at /Users/mahesh/Library/Android/sdk
    • Platform android-31, build-tools 31.0.0
    • ANDROID_HOME = /Users/mahesh/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 13.1, Build version 13A1030d
    • CocoaPods version 1.10.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)

[✓] IntelliJ IDEA Community Edition (version 2021.2.1)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 60.1.4
    • Dart plugin version 212.5080.8

[✓] VS Code (version 1.63.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.32.0

[✓] Connected device (4 available)
    • Redmi K20 Pro (mobile) • 192.168.1.2:5555                     • android-arm64  • Android 11 (API 30)
    • iPhone 12 Pro (mobile) • B622CBB7-F906-4FA7-8F49-FACEAAC905AB • ios            • com.apple.CoreSimulator.SimRuntime.iOS-14-5 (simulator)
    • macOS (desktop)        • macos                                • darwin-arm64   • macOS 12.1 21C52 darwin-arm
    • Chrome (web)           • chrome                               • web-javascript • Google Chrome 96.0.4664.110

• No issues found!

cc: @gspencergoog

@maheshmnj maheshmnj added a: text input Entering text in a text field or keyboard related problems f: focus Focus traversal, gaining or losing focus found in release: 2.8 Found to occur in 2.8 found in release: 2.9 Found to occur in 2.9 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on c: regression It was better in the past than it is now and removed in triage Presently being triaged by the triage team labels Jan 10, 2022
@maheshmnj maheshmnj changed the title Unable to show selection in TextField if it is unfocused. Programmatically select text in unfocused textfield not working Jan 10, 2022
@HansMuller HansMuller added the f: material design flutter/packages/flutter/material repository. label Jan 10, 2022
@HansMuller
Copy link
Contributor

CC @justinmc

@justinmc justinmc self-assigned this Jan 10, 2022
@justinmc
Copy link
Contributor

Here's the PR that caused this: #86796. CC @LongCatIsLooong

I want to say that this is working as intended, but I think that @searchy2 mentions something that is a bug in #96339 (comment).

I just tried this on native Mac and web, and selection isn't shown when the field doesn't have focus. Flutter should probably match that behavior.

I think the real bug is that there should be a way to prevent the focus from going to a button, for example in the case of @searchy2's bold etc. buttons. I think the issue that addresses this problem is #86972. I specifically brought up the bold button thing here. The solution there may be to refactor FocusTrap.

@imaachman @searchy2 Do you guys agree with that assessment? Is solving #86972 the way to fix the problems you're having?

@imaachman
Copy link
Author

@justinmc You're right about buttons and FocusTrap refactor might be a solution to that problem.

However, our text editor also has text fields for entering the font size, spacing, etc. In that scenario, user needs to focus on the property text field to edit it. We want to keep the selection intact in the main text field so that user know exactly which characters are being edited.

That's why we need the control of selection UI even when a text field loses focus. I hope this makes sense.

@rayliverified
Copy link

rayliverified commented Jan 14, 2022

Off topic The FocusManager is one of our biggest problems that we're constantly fighting to get to work as expected.

The issue is we don't have control or visibility into what is currently focused. Many of our features depend upon focus but we don't know what is focused!

There are two things that would probably solve 80% of the issues we're running into.

  1. Expose what widget is currently focused.
  2. Allow Focus to be "locked" to a widget.

@gspencergoog
Copy link
Contributor

gspencergoog commented Jan 14, 2022

@searchy2 The FocusManager.instance.primaryFocus accessor contains the currently focused FocusNode.

You might want to also check out this article for more details on the focus system.

Your comment is off-topic for this issue. If you have more questions, please ask on Discord or in Stack Overflow. If you have a feature request, please file a separate issue.

@rayliverified
Copy link

Thank you @gspencergoog for the info and the link to that article.

@justinmc justinmc removed their assignment Feb 4, 2022
@justinmc
Copy link
Contributor

justinmc commented Aug 1, 2022

This should be fixed in master as of #107262. @imaachman let me know if you've still got any problems here.

You'll have to wrap anything that shouldn't steal focus from a text field in TextFieldTapRegion. Below I've modified the original code sample from this issue to make it work:

Code
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late final TextEditingController controller;
  late final FocusNode focusNode;

  @override
  void initState() {
    super.initState();

    focusNode = FocusNode(debugLabel: 'TextField FocusNode');
    controller = TextEditingController();
    controller.text = 'Select this text';
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
          child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          SizedBox(
            width: 200,
            child: TextField(
              focusNode: focusNode,
              controller: controller,
            ),
          ),
          const SizedBox(width: 16),
          IconButton(
            tooltip: 'Focus text field',
            onPressed: () => focusNode.requestFocus(),
            icon: const Icon(Icons.center_focus_strong),
          ),
        ],
      )),
      // NEW: Add TextFieldTapRegion around things that shouldn't steal focus
      // from text fields.
      floatingActionButton: TextFieldTapRegion(
        child: FloatingActionButton(
          onPressed: () {
            // NEW: You'll have to request focus here if you also want the field
            // to gain focus.
            focusNode.requestFocus();
            controller.selection = controller.selection
                .copyWith(baseOffset: 0, extentOffset: controller.text.length);
          },
          tooltip: 'Select text',
          child: const Icon(Icons.select_all_rounded),
        ),
      ),
    );
  }

  @override
  void dispose() {
    focusNode.dispose();
    controller.dispose();
    super.dispose();
  }
}

@justinmc justinmc closed this as completed Aug 1, 2022
@imaachman
Copy link
Author

imaachman commented Aug 2, 2022

@justinmc Thank you for creating TextFieldTapRegion. This widget does help with text field retaining the focus when buttons are pressed.

But it does not help in our use case, which is, text selection being intact even if the text field is unfocused.

Here's what I exactly mean: https://www.loom.com/share/36225c2fdeec495ebf69284af45b10d1

In this example, the selection UI remains intact when FAB is pressed because the field does not lose focus. But when we tap on the second text field (and focus is shifted), the selection UI disappears.

We do not want that to happen because the user should know which characters are currently selected when they try to edit the font size using second text field.

Reference Code
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late final TextEditingController controller;
  late final FocusNode focusNode;

  @override
  void initState() {
    super.initState();

    focusNode = FocusNode(debugLabel: 'TextField FocusNode');
    controller = TextEditingController();
    controller.text = 'Select this text';
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
          child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              SizedBox(
                width: 200,
                child: TextField(
                  focusNode: focusNode,
                  controller: controller,
                ),
              ),
              const SizedBox(width: 16),
              IconButton(
                tooltip: 'Focus text field',
                onPressed: () => focusNode.requestFocus(),
                icon: const Icon(Icons.center_focus_strong),
              ),
            ],
          ),
          const SizedBox(
            width: 200,
            child: TextFieldTapRegion(
              child: TextField(
                decoration: InputDecoration(hintText: 'Enter font size'),
              ),
            ),
          ),
        ],
      )),
      // NEW: Add TextFieldTapRegion around things that shouldn't steal focus
      // from text fields.
      floatingActionButton: TextFieldTapRegion(
        child: FloatingActionButton(
          onPressed: () {
            // NEW: You'll have to request focus here if you also want the field
            // to gain focus.
            // focusNode.requestFocus();
            // controller.selection = controller.selection
            //     .copyWith(baseOffset: 0, extentOffset: controller.text.length);
          },
          tooltip: 'Select text',
          child: const Icon(Icons.select_all_rounded),
        ),
      ),
    );
  }

  @override
  void dispose() {
    focusNode.dispose();
    controller.dispose();
    super.dispose();
  }
}

@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
a: text input Entering text in a text field or keyboard related problems c: regression It was better in the past than it is now f: focus Focus traversal, gaining or losing focus f: material design flutter/packages/flutter/material repository. found in release: 2.8 Found to occur in 2.8 found in release: 2.9 Found to occur in 2.9 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on
Projects
None yet
Development

No branches or pull requests

7 participants