Skip to content

TextEditingController is not updating cursor position #65547

Closed as not planned
Closed as not planned

Description

@lslv1243

After I updated to Flutter 1.20.3 I am having a problem with the TextEditingController. On iOS it still works as before but, on Android, the controller is not notifying listeners when value is empty. It should notify when I had some value and erased it as it does on iOS.

flutter doctor -v
[✓] Flutter (Channel stable, 1.20.3, on Mac OS X 10.15.6 19G73, locale pt)
    • Flutter version 1.20.3 at /Users/leonardosilva/development/flutter/flutter
    • Framework revision 216dee60c0 (9 days ago), 2020-09-01 12:24:47 -0700
    • Engine revision d1bc06f032
    • Dart version 2.9.2

 
[!] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
    • Android SDK at /Users/leonardosilva/Library/Android/sdk
    • Platform android-29, build-tools 29.0.3
    • Java binary at: /Applications/Android
      Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build
      1.8.0_242-release-1644-b3-6222593)
    ! Some Android licenses not accepted.  To resolve this, run: flutter doctor
      --android-licenses

[✓] Xcode - develop for iOS and macOS (Xcode 11.6)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 11.6, Build version 11E708
    • CocoaPods version 1.8.4

[✓] Android Studio (version 4.0)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 49.0.2
    • Dart plugin version 193.7547
    • Java version OpenJDK Runtime Environment (build
      1.8.0_242-release-1644-b3-6222593)

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

[✓] Connected device (1 available)
    • Mi A2 (mobile) • d73165 • android-arm64 • Android 10 (API 29)

! Doctor found issues in 1 category.

Activity

  1. added
    a: text inputEntering text in a text field or keyboard related problems
    p: material_uimaterial_ui package in flutter/packages
    frameworkflutter/packages/flutter repository. See also f: labels.
    c: regressionIt was better in the past than it is now
    on Sep 10, 2020
  2. xu-baolin commented on Sep 11, 2020

    @xu-baolin
    Member

    @lslv1243 Hi
    I cannot reproduce the problem in the version you mentioned and the latest version, please provide a minimal complete reproducible code sample that shows the issue.

    Sample Code
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Retrieve Text Input',
          home: MyCustomForm(),
        );
      }
    }
    
    // Define a custom Form widget.
    class MyCustomForm extends StatefulWidget {
      @override
      _MyCustomFormState createState() => _MyCustomFormState();
    }
    
    // Define a corresponding State class.
    // This class holds data related to the Form.
    class _MyCustomFormState extends State<MyCustomForm> {
      // Create a text controller and use it to retrieve the current value
      // of the TextField.
      final myController = TextEditingController(text: 'a');
    
      @override
      void initState() {
        super.initState();
    
        myController.addListener(_printLatestValue);
      }
    
      @override
      void dispose() {
        // Clean up the controller when the widget is removed from the widget tree.
        // This also removes the _printLatestValue listener.
        myController.dispose();
        super.dispose();
      }
    
      _printLatestValue() {
        print("Second text field: ${myController.text}");
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Retrieve Text Input'),
          ),
          body: Padding(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              children: <Widget>[
                TextField(
                  onChanged: (text) {
                    print("First text field: $text");
                  },
                ),
                TextField(
                  controller: myController,
                ),
              ],
            ),
          ),
        );
      }
    }
    
    flutter doctor -v
    PS F:\flutter_dev\src_new\flutter> flutter doctor -v
    [√] Flutter (Channel stable, 1.20.3, on Microsoft Windows [Version 10.0.17763.615], locale en-US)
        • Flutter version 1.20.3 at F:\flutter_dev\src_new\flutter
        • Framework revision 216dee60c0 (9 days ago), 2020-09-01 12:24:47 -0700
        • Engine revision d1bc06f032
        • Dart version 2.9.2
        • Pub download mirror https://pub.flutter-io.cn
        • Flutter download mirror https://storage.flutter-io.cn
    
    [!] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
        • Android SDK at C:\Users\Administrator\AppData\Local\Android\sdk
        • Platform android-29, build-tools 29.0.3
        • Java binary at: C:\Program Files\Android\Android Studio1\jre\bin\java
        • Java version OpenJDK Runtime Environment (build 1.8.0_212-release-1586-b04)
        X Android license status unknown.
          Try re-installing or updating your Android SDK Manager.
          See https://developer.android.com/studio/#downloads or visit
          https://flutter.dev/docs/get-started/install/windows#android-setup for detailed instructions.
    
    [√] Android Studio (version 3.6)
        • Android Studio at C:\Program Files\Android\Android Studio1
        • Flutter plugin version 48.1.1
        • Dart plugin version 192.8052
        • Java version OpenJDK Runtime Environment (build 1.8.0_212-release-1586-b04)
    
    [√] VS Code (version 1.48.2)
        • VS Code at C:\Users\Administrator\AppData\Local\Programs\Microsoft VS Code
        • Flutter extension version 3.14.1
    
    [√] Connected device (1 available)
        • PDCM00 (mobile) • 9LL7VO8XUOIN75ZH • android-arm64 • Android 10 (API 29)
    
    ! Doctor found issues in 1 category.
    PS F:\flutter_dev\src_new\flutter>
    
  3. lslv1243 commented on Sep 11, 2020

    @lslv1243
    Author

    @xu-baolin Hi
    I was using it actually only as a hidden input for my custom styled input and did not look at the exact input behavior. This difference has started in the newer version but is not as simple as I described, what is happening is that the cursor is behaving differently on Android than it does on iOS and it did on Android.

    On Android before and iOS now, after erasing, the cursor stays to the right-hand side of the number.
    On Android now, after erasing, the cursor stays to the left-hand side of the number.
    This new behavior made my code break, because if the cursor is to the left-right side of the text and I try to erase, nothing happens, that is why I described the way I did.

    I edited your code to show this behavior.

    Sample code
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Retrieve Text Input',
          home: MyCustomForm(),
        );
      }
    }
    
    // Define a custom Form widget.
    class MyCustomForm extends StatefulWidget {
      @override
      _MyCustomFormState createState() => _MyCustomFormState();
    }
    
    // Define a corresponding State class.
    // This class holds data related to the Form.
    class _MyCustomFormState extends State<MyCustomForm> {
      // Create a text controller and use it to retrieve the current value
      // of the TextField.
      _CurrencyTextController myController;
    
      @override
      void initState() {
        super.initState();
        myController = _WithoutCentsTextController();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Retrieve Text Input'),
          ),
          body: Padding(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              children: <Widget>[
                TextField(
                  controller: myController,
                ),
              ],
            ),
          ),
        );
      }
    }
    
    abstract class _CurrencyTextController implements TextEditingController {
      double get numberValue;
      void updateValue(double value);
    }
    
    class _WithoutCentsTextController extends TextEditingController
        implements _CurrencyTextController {
      _WithoutCentsTextController({double initialValue}) {
        this.addListener(() {
          this.updateValue(this.numberValue);
        });
    
        this.updateValue(initialValue ?? 0);
      }
    
      @override
      double get numberValue => (int.tryParse(value.text) ?? 0).toDouble();
    
      @override
      void updateValue(double value) {
        final formatted = value.toInt().toString();
        if (formatted != this.text) {
          this.text = formatted;
        }
      }
    }
  4. pedromassangocode commented on Sep 11, 2020

    @pedromassangocode

    Hi @lslv1243
    Does the code bellow reproduce the issue you are facing?

    Code
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      TextEditingController myController;
    
      @override
      void initState() {
        super.initState();
        myController = TextEditingController();
        myController.addListener(() {
          print('called: ${myController.text}');
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            body: Center(
              child: TextField(
                controller: myController,
              ),
            ),
          ),
        );
      }
    }
    
  5. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Sep 11, 2020
  6. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Sep 11, 2020
  7. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Sep 11, 2020
  8. lslv1243 commented on Sep 11, 2020

    @lslv1243
    Author

    No, it does not. As I described afterwards, it has to do with the cursor #65547 (comment). It is not as simple as I described initially.

  9. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Sep 11, 2020
  10. pedromassangocode commented on Sep 15, 2020

    @pedromassangocode

    I noticed that we have a breaking change here.

    Testing on iOS with Flutter 1.17.5, the text field does updates the position of the indicator automatically after clearing the text field but it does not while testing with Flutter 1.20.3.

    This can be worked around by updating the selection while changing the text in the controller:

          // this is not updating the selection (aka the position of the indicator)
          // controller.text = formatted;
          
          // Use value property to update both the text and selection
          controller.value = TextEditingValue(
            text: text,
            selection: TextSelection(baseOffset: formatted.length, extentOffset: formatted.length)
          );

    Testing with Flutter 1.17.5

    gif

    Testing with Flutter 1.20.3

    gif

    flutter doctor -v
    
    
  11. 10 remaining items

  12. added and removed
    team-designOwned by Design Languages team
    triaged-designTriaged by Design Languages team
    on Oct 24, 2024
  13. added
    P2Important issues not at the top of the work list
    on Oct 24, 2024
  14. justinmc commented on Oct 24, 2024

    @justinmc
    Contributor

    @LongCatIsLooong to check if this is still reproducible.

  15. LongCatIsLooong commented on Oct 29, 2024

    @LongCatIsLooong
    Contributor

    The selection is reset if you use the text setter:

        if (formatted != this.text) {
          this.text = formatted;
        }

    See https://main-api.flutter.dev/flutter/widgets/TextEditingController/text.html

    I think we should deprecate this setter or mark it visibleForTesting, as it has been a major source of confusion.

  16. github-actions commented on Nov 12, 2024

    @github-actions

    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.

  17. locked as resolved and limited conversation to collaborators on Nov 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work lista: text inputEntering text in a text field or keyboard related problemsc: regressionIt was better in the past than it is nowfound in release: 3.3Found to occur in 3.3found in release: 3.6Found to occur in 3.6frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onp: material_uimaterial_ui package in flutter/packagesteam-text-inputOwned by Text Input teamtriaged-text-inputTriaged by Text Input team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions