问题
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