【问题标题】:Material Textfield text is displayed backwards but CupertinoTextfield text is displayed correctly Flutter材质 Textfield 文本向后显示,但 CupertinoTextfield 文本正确显示 Flutter
【发布时间】:2020-09-26 08:29:06
【问题描述】:

我有一个文本字段连接到它的TextEditingController()。在onChanged: 回调中,我执行文本检查以仅允许时间输入。 在 iOS 上运行时,使用CupertinoTextfield 并且它的行为与预期一样,每次输入光标都会移动,因此下一个数字位于正确的位置,因此输入 1000 将导致 10:00。 当在 web 或 Android Material Textfield 上运行时,问题是文本向后显示,因为光标停留在第一个位置,因此输入 1000 将导致 00:01 .. 我尝试启用 autofocus: true ,但没有帮助。我尝试使用textDirection: TextDirection.ltr,,但也没有修复它。我还尝试了另一个帖子中的解决方案,获取控制器选择并将其重新应用于选中的文本,但它也没有帮助。 我想为 Material Textfield 设置什么? 一如既往,非常感谢您的时间和帮助。

这是小部件:

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);
                                    },
                                  ),
                      ),

这是文本检查方法:

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;
    }
  }

【问题讨论】:

    标签: flutter textfield


    【解决方案1】:

    由于 jwehrle 的回答 how to set cursor position at the end of the value in flutter in textfield? ,将近一个月后,我找到了问题的解决方案。实际上,我向 Flutter 团队提出了一个问题,因为Material Textfield 在将操纵文本分配给其TextEditingController 时的行为与CupertinoTextfield 不同,而且它似乎与平台相关,我只在 Web 和 iPad 上对其进行了测试。 我认为这个解决方案更像是一种解决方法,因为这不是必需的,因为 iOS 上的 CupertinoTextfield 不需要它。

    onChanged: 回调中,在将操纵的输入文本分配给控制器后添加:

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

    使用中:

    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));
                                        },
                                      ),
                          ),
    

    2020 年 8 月 8 日更新:

    当我升级到 Catalina、Android Studio 4.0 时,iOS 现在也需要解决方法。不确定这是否是由于 iOS 13.5 或 Flutter 的变化造成的。但在网络上,它现在会成对打乱数字。 看起来像固定的东西和坏的东西..

    在 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!
    

    2021 年 2 月 4 日更新

    在将文本格式化为之后,而不是将 onChanged 回调中的新文本字段的值分配给它的控制器的 .text 参数

    monMorOp.text = validateTimeFormat(value);
    

    然后通过将控制器的.text.length 数量偏移来替换控制器选择

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

    我现在将新的格式化文本字段文本分配给控制器的.value,并将其选择位置偏移文本字段的格式化值

     onChanged: (value) {
         value = validateTimeFormat(value);
         monMorCl.value = TextEditingValue(
               text: value,
               selection: TextSelection.collapsed(offset: value.length));
     },
    

    希望它能对其他人有所帮助,因为我看到最近任何 Flutter/Dart 更新都发生了很大变化。 干杯

    【讨论】:

    • @gogobebe2 确实它不再工作了.. 我无法在 iPad 上测试,但运行应用程序一个 android 会出现与 web 上相同的问题..
    • @gogobebe2 你解决了吗?请检查我的回答中的 2 月更新,看看是否适合您。干杯。
    【解决方案2】:
    class FixedOffsetTextEditingController extends TextEditingController {
      @override
      set text(String newText) {
        value = value.copyWith(
          text: newText,
          selection: TextSelection.collapsed(offset: newText.length),
          composing: TextRange.empty,
        );
      }
    }
    

    截至 2021 年 4 月 2 日,这对我有用 :)

    【讨论】:

    • 非常好,然后从文本字段的 onChanged: (value) { } 回调中您刚刚设置了 controller.text = value ?是否在 setState(){} 内?非常感谢。
    • 这里不走运,每当我将onChanged 值分配给TextEditingController.text 时,它都会向后显示它,因为光标停留在文本字段的开头。因此,如果我在分配TextEditingController.text onChanged 值之前使用我的验证器(它按预期工作并且不是这里的问题),它会被打乱.. 你使用的是什么 Flutter 通道和 Dart 版本?我在 Channel stable 1.22.6 / Dart 版本 2.10.5
    • 我更新了我的答案,因为我找到了一个可行的解决方案,如果你想检查它是否也解决了你的问题。无需扩展 TextEditing 控制器。使用.value 而不是.text 参数,它确实可以正常工作。干杯
    【解决方案3】:

    我来这里是为了寻找类似的东西,但我很确定这不是 Material TextField 的直接错误,因为如果我在 Android 模拟器上编译 + 运行它就可以了。但是在为桌面编译相同的代码时是错误的。

    您是否报告了错误?

    对我来说还是坏了@

    Flutter 2.0.5 • channel stable • https://github.com/flutter/flutter.git
    Framework • revision adc687823a (2 weeks ago) • 2021-04-16 09:40:20 -0700
    Engine • revision b09f014e96
    Tools • Dart 2.12.3
    

    啊哈:这是一个 gtk+ 版本问题,请参阅:https://github.com/flutter/flutter/issues/47745 - 你至少需要 3.24.27(我有 3.24.26 ... 典型)

    【讨论】:

    • 你在我的回答中看到Update 4 Feb 2021了吗?如果将文本字段的 onChanged 回调中的 value 分配给文本字段的控制器 .value 属性(而不是将其分配给其 .text 参数,该参数仅用于在页面初始化时分配初始值)和偏移量,则它可以工作value.length 数量的光标..
    • 我做到了,但我通过升级 gtk+ 而不是解决它来修复我的问题
    猜你喜欢
    • 2016-01-04
    • 1970-01-01
    • 2021-07-23
    • 2019-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-24
    • 2022-06-24
    相关资源
    最近更新 更多