Material Textfield text is displayed backwards but CupertinoTextfield text is displayed correctly Flutter

房东的猫 提交于 2020-08-10 20:22:48

问题


I have a textfield connected to its TextEditingController(). Inside the onChanged: callback I perform a text check to only allow for time input. When running on iOS CupertinoTextfield is used and it behaves as expected, at every input cursor moves so next digit is at the right position, so inputting 1000 will result in 10:00. When running on web or Android Material Textfield is used instead, the problem is that text is displayed backward as the cursor stays at first position so inputting 1000 will result in 00:01 .. I tried enabling autofocus: true , but doesn't help. I tried with textDirection: TextDirection.ltr, but didn't fixit either. I also tried a solution from another post here grabbing the controller selection and reapplying it on the checked text but it didn't help either. What am I missing to set for Material Textfield ? As always thank you very much for your time and help.

This is the widget:

Expanded(
                        flex: 2,
                        child: kIsWeb
                            ? TextField(
                                keyboardType: TextInputType.numberWithOptions(),
                                textDirection: TextDirection.ltr,
                                autofocus: true,
                                controller: monMorOp,
                                onChanged: (value) {
                                  TextSelection previousSelection =
                                      monMorOp.selection;
                                  monMorOp.text = validateTimeFormat(value);
                                  monMorOp.selection = previousSelection;
                                },
                              )
                            : Platform.isIOS
                                ? CupertinoTextField(
                                    keyboardType:
                                        TextInputType.numberWithOptions(),
                                    controller: monMorOp,
                                    onChanged: (value) {
                                      monMorOp.text = validateTimeFormat(value);
                                    },
                                  )
                                : TextField(
                                    keyboardType:
                                        TextInputType.numberWithOptions(),
                                    controller: monMorOp,
                                    onChanged: (value) {
                                      monMorOp.text = validateTimeFormat(value);
                                    },
                                  ),
                      ),

an this is the text checking method :

String validateTimeFormat(String value) {
    print('call back method called');
//    String numb = event.text;
    print('input text is $value');
    String cleanNumb = value.replaceAll(RegExp(':'), '').substring(0);
    print('cleaned input text is $cleanNumb');
    RegExp isDigit = RegExp(r'^[\d]{1,4}$'); // is digit 1 to 4 characters
//    RegExp isDigit = RegExp(r'^[\d]$'); // is digit
    RegExp input;
    String text;
    int lenght;
    String replaced;

    if (isDigit.hasMatch(cleanNumb)) {
      print('text is 1-4 digits');
      text = cleanNumb;
      lenght = text.length;
//      print('lenght is $lenght');

      if (lenght == 1) {
        // first digit
        //allow 0-2
        input = RegExp(r'^[0-2]$');
        input.hasMatch(text[0])
            ? print('text is : $text')
            : print('text is: not valid');
        return input.hasMatch(text[lenght - 1]) ? text : '';
      } else if (lenght == 2) {
        // second digit
        int first = int.parse(text[0]);
        print('firstDigit is $first');
        if (first == 008 || first == 1) {
          // allow 0-9
          input = RegExp(r'^[0-9]$');
          input.hasMatch(text[lenght - 1])
              ? print('text is : $text')
              : print('text is : ${text.substring(0, lenght - 1)}');
          return input.hasMatch(text[lenght - 1])
              ? text
              : text.substring(0, lenght - 1);
        } else {
          // allow 0-3
          input = RegExp(r'^[0-3]$');
          input.hasMatch(text[lenght - 1])
              ? print('text is : $text')
              : print('text is : ${text.substring(0, lenght - 1)}');
          return input.hasMatch(text[lenght - 1])
              ? text
              : text.substring(0, lenght - 1);
        }
      }
      if (lenght == 3) {
        //third digit
        // add : at lenght-1
        // allow 0-5
        input = RegExp(r'^[0-5]$');
        input.hasMatch(text[lenght - 1])
            ? replaced = text.replaceRange(2, lenght, ':${text.substring(2)}')
            : replaced = text.substring(0, lenght - 1);
        print('text is : $replaced');
        return replaced;
      }
      if (lenght == 4) {
        // fourth digit
        // allow 0-9
        input = RegExp(r'^[0-9]$');
        input.hasMatch(text[lenght - 1])
            ? replaced = text.replaceRange(2, lenght, ':${text.substring(2)}')
            : replaced = text.substring(0, lenght - 1);
        print('text is : $replaced');
        return replaced;
      }
    } else {
      // discard extra digit
      print('more than 4 digits');
      lenght = cleanNumb.length;
      replaced =
          cleanNumb.replaceRange(2, lenght, ':${cleanNumb.substring(2, 4)}');
      print('text is : $replaced');
      return replaced;
    }
  }

回答1:


After almost a month I found a solution to the problem thanks to jwehrle answer here how to set cursor position at the end of the value in flutter in textfield?. I actually filed an issue to the Flutter team as Material Textfield behaves different from CupertinoTextfield when assigning a manipulated text to its TextEditingController and it seems to be platform related, I only tested it on web and iPad. I think of this solution more of a workaround as this shouldn't be necessary as it isn't needed in CupertinoTextfield on iOS.

In onChanged: callback add this after assigning the manipulated input text to the controller:

textfieldController.selection = TextSelection.fromPosition(TextPosition(offset: textfieldController.text.length));

In use:

Expanded(
                        flex: 2,
                        child: UniversalPlatform.isWeb
                            ? TextField(
                                keyboardType: TextInputType.numberWithOptions(),
                                textDirection: TextDirection.ltr,
                                autofocus: true,
                                controller: monMorOp,
                                style: TextStyle(
                                    color: Colors.white,
                                    fontSize: 15,
                                    fontWeight: FontWeight.w500),
                                onChanged: (value) {
                                  monMorOp.text = validateTimeFormat(value);
                                  monMorOp.selection =
                                      TextSelection.fromPosition(TextPosition(
                                          offset: monMorOp.text.length));
                                },
                              )
                            : UniversalPlatform.isIOS
                                ? CupertinoTextField(
                                    keyboardType:
                                        TextInputType.numberWithOptions(),
                                    controller: monMorOp,
                                    style: TextStyle(
                                        color: Colors.white,
                                        fontSize: 15,
                                        fontWeight: FontWeight.w500),
                                    onChanged: (value) {
                                      monMorOp.text = validateTimeFormat(value);
                                    },
                                  )
                                : TextField(
                                    keyboardType:
                                        TextInputType.numberWithOptions(),
                                    controller: monMorOp,
                                    style: TextStyle(
                                        color: Colors.white,
                                        fontSize: 15,
                                        fontWeight: FontWeight.w500),
                                    onChanged: (value) {
                                      monMorOp.text = validateTimeFormat(value);
                                      monMorOp.selection =
                                          TextSelection.fromPosition(
                                              TextPosition(
                                                  offset:
                                                      monMorOp.text.length));
                                    },
                                  ),
                      ),

update 8 aug 2020:

As I upgraded to Catalina, Android Studio 4.0 the workaround is now needed also for iOS. Not sure if it's due to a change in iOS 13.5 or Flutter..

flutter doctor on Catalina:

[✓] Flutter (Channel master, 1.21.0-8.0.pre.98, on Mac OS X 10.15.4 19E287, locale it-IT)
    • Flutter version 1.21.0-8.0.pre.98 at /Users/vinnytwice/Developer/flutter
    • Framework revision 77b4505c80 (31 hours ago), 2020-08-06 18:51:02 -0700
    • Engine revision cd3ea1e839
    • Dart version 2.10.0 (build 2.10.0-3.0.dev fcafd43f2c)

 
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.1)
    • Android SDK at /Users/vinnytwice/Library/Android/sdk
    • Platform android-29, build-tools 30.0.1
    • 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)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 11.5)
    • Xcode at /Volumes/ProjectsSSD/Xcode.app/Contents/Developer
    • Xcode 11.5, Build version 11E608c
    • CocoaPods version 1.9.3

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

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

[✓] Connected device (3 available)
    • iPad Pro (12.9-inch) (4th generation) (mobile) • 08E2351F-A170-4C2E-A8DE-8FED3B5E3124 • ios            •
      com.apple.CoreSimulator.SimRuntime.iOS-13-5 (simulator)
    • Web Server (web)                               • web-server                           • web-javascript • Flutter
      Tools
    • Chrome (web)                                   • chrome                               • web-javascript • Google
      Chrome 84.0.4147.105

• No issues found!


来源:https://stackoverflow.com/questions/62244027/material-textfield-text-is-displayed-backwards-but-cupertinotextfield-text-is-di

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!