#regex #flutter #timer #textfield #textformfield
Вопрос:
Кто-нибудь может помочь выяснить, как настроить виджет текстового поля или текстового поля для ввода времени в формате чч:мм:сс?
Форматирование должно отображаться в поле в реальном времени, поэтому начальные нули будут заменены во время ввода пользователем.
Например, если нам нужно ввести 1 час 59 минут и 27 секунд, это должно работать следующим образом:
- 00:00:00 — текстовая подсказка перед вводом текста
- 00:00:01 — начинает печатать и набирает 1
- 00:00:15 — набрано 5
- 00:01:59 — набрано 9
- 00:15:92 — набрано 2 (здесь допустимо 92 секунды, их можно преобразовать после завершения ввода)
- 01:59:27 — набрано 7
Он работает аналогично таймеру во встроенном приложении для часов Android.
Я пытался использовать пакет mask_text_input_formatter, но он работает не так, как мне нужно. Кроме того, я не хочу использовать сборщики времени.
import 'package:flutter/services.dart'; import 'package:mask_text_input_formatter/mask_text_input_formatter.dart'; class TimeInputField extends StatefulWidget { TimeInputField({Key key}) : super(key: key); @override _TimeInputFieldState createState() =gt; _TimeInputFieldState(); } class _TimeInputFieldState extends Statelt;TimeInputFieldgt; { TextEditingController _txtTimeController = TextEditingController(); final MaskTextInputFormatter timeMaskFormatter = MaskTextInputFormatter(mask: '##:##:##', filter: {"#": RegExp(r'[0-9]')}); @override Widget build(BuildContext context) { return TextFormField( controller: _txtTimeController, keyboardType: TextInputType.numberWithOptions(decimal: false), decoration: InputDecoration( hintText: '00:00:00', ), inputFormatters: lt;TextInputFormattergt;[ timeMaskFormatter // Not sure if it can be done with RegExp or a custom class here instead ], ); } }
Любая помощь будет очень признательна!
Ответ №1:
Обновленный Код:
import 'package:flutter/material.dart'; import 'package:flutter/services.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: TimeInputField(), ); } } class TimeInputField extends StatefulWidget { const TimeInputField({Key? key}) : super(key: key); @override _TimeInputFieldState createState() =gt; _TimeInputFieldState(); } class _TimeInputFieldState extends Statelt;TimeInputFieldgt; { String hrCounter = '00'; String minCounter = '00'; String secCounter = '00'; String temp=""; final TextEditingController _controller = TextEditingController(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Stack Overflow"), ), body: Center( child: Padding( padding: const EdgeInsets.all(8.0), child: Stack( children: [ SizedBox( width: 250, child: TextFormField( controller: _controller, keyboardType: const TextInputType.numberWithOptions(decimal: false), inputFormatters: [ LengthLimitingTextInputFormatter(9), ], decoration: InputDecoration( hintText: '$hrCounter:$minCounter:$secCounter', floatingLabelBehavior: FloatingLabelBehavior.always, labelText: '$hrCounter:$minCounter:$secCounter'), onChanged: (val) { String y=""; switch (val.length) { case 0: setState(() { hrCounter = "00"; minCounter = "00"; secCounter = "00"; }); break; case 1: setState(() { secCounter = "0" val; temp=val; _controller.value = _controller.value.copyWith( text: hrCounter ":" minCounter ":" secCounter, selection: const TextSelection.collapsed(offset: 8), ); }); break; default: setState((){ for(int i=1;ilt;=val.length-1;i ){ y=y val.substring(i,i 1); } y=y.replaceAll(":", ""); val=y.substring(0,2) ":" y.substring(2,4) ":" y.substring(4,6); temp=val; _controller.value = _controller.value.copyWith( text: val, selection: const TextSelection.collapsed(offset: 8), ); }); break; } }, ), ), ], ), ), ), ); } }
Комментарии:
1. Спасибо вам за вашу помощь. Хотя у меня бы это не сработало. У меня не будет ярлыка для моей области. Поскольку текст контроллера обновляется после 6-го регистра цифр в предоставленном коде, он обновит значение редактирования текста только после ввода 6 цифр. Мне нужно, чтобы он обновлялся после каждой цифры. Обновление текстового значения контроллера после каждого случая в коммутаторе не позволит мне вводить что-либо после первой цифры.
2. Попробуйте последнюю версию.
3. Это не сработает. При использовании этого кода длина значения контроллера всегда будет либо 1, либо 6 (если оно не пустое). Я опубликую свое собственное решение. Еще раз спасибо за ваш вклад.
Ответ №2:
Я использовал TextInputFormatter в текстовом поле вместо OnChanged. Это позволяет получить доступ к старому значению и отформатировать новый ввод в зависимости от того, был ли добавлен или удален новый символ. Это также позволяет использовать регулярное выражение для приема только чисел. Это было бы решением:
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'dart:math' as math; class TimeInputField extends StatefulWidget { TimeInputField({Key key}) : super(key: key); @override _TimeInputFieldState createState() =gt; _TimeInputFieldState(); } class _TimeInputFieldState extends Statelt;TimeInputFieldgt; { TextEditingController _txtTimeController = TextEditingController(); @override Widget build(BuildContext context) { return TextFormField( controller: _txtTimeController, keyboardType: TextInputType.numberWithOptions(decimal: false), decoration: InputDecoration( hintText: '00:00:00', ), inputFormatters: lt;TextInputFormattergt;[ TimeTextInputFormatter() // This input formatter will do the job ], ); } } class TimeTextInputFormatter extends TextInputFormatter { RegExp _exp; TimeTextInputFormatter() { _exp = RegExp(r'^[0-9:]
Комментарии:
1. Добро пожаловать в Stack Overflow и спасибо, что вернулись к вашему вопросу, чтобы поделиться своим решением с сообществом. Не могли бы вы, пожалуйста, отредактировать свой ответ, включив в него объяснение вашего кода? Это поможет будущим читателям лучше понять, что происходит, и особенно тем членам сообщества, которые новички в языке и изо всех сил пытаются понять концепции.
); } @override TextEditingValue formatEditUpdate( TextEditingValue oldValue, TextEditingValue newValue, ) { if (_exp.hasMatch(newValue.text)) { TextSelection newSelection = newValue.selection; String value = newValue.text; String newText; String leftChunk = ''; String rightChunk = ''; if (value.length gt;= 8) { if (value.substring(0, 7) == '00:00:0') { leftChunk = '00:00:'; rightChunk = value.substring(leftChunk.length 1, value.length); } else if (value.substring(0, 6) == '00:00:') { leftChunk = '00:0'; rightChunk = value.substring(6, 7) ":" value.substring(7); } else if (value.substring(0, 4) == '00:0') { leftChunk = '00:'; rightChunk = value.substring(4, 5) value.substring(6, 7) ":" value.substring(7); } else if (value.substring(0, 3) == '00:') { leftChunk = '0'; rightChunk = value.substring(3, 4) ":" value.substring(4, 5) value.substring(6, 7) ":" value.substring(7, 8) value.substring(8); } else { leftChunk = ''; rightChunk = value.substring(1, 2) value.substring(3, 4) ":" value.substring(4, 5) value.substring(6, 7) ":" value.substring(7); } } else if (value.length == 7) { if (value.substring(0, 7) == '00:00:0') { leftChunk = ''; rightChunk = ''; } else if (value.substring(0, 6) == '00:00:') { leftChunk = '00:00:0'; rightChunk = value.substring(6, 7); } else if (value.substring(0, 1) == '0') { leftChunk = '00:'; rightChunk = value.substring(1, 2) value.substring(3, 4) ":" value.substring(4, 5) value.substring(6, 7); } else { leftChunk = ''; rightChunk = value.substring(1, 2) value.substring(3, 4) ":" value.substring(4, 5) value.substring(6, 7) ":" value.substring(7); } } else { leftChunk = '00:00:0'; rightChunk = value; } if (oldValue.text.isNotEmpty amp;amp; oldValue.text.substring(0, 1) != '0') { if (value.length gt; 7) { return oldValue; } else { leftChunk = '0'; rightChunk = value.substring(0, 1) ":" value.substring(1, 2) value.substring(3, 4) ":" value.substring(4, 5) value.substring(6, 7); } } newText = leftChunk rightChunk; newSelection = newValue.selection.copyWith( baseOffset: math.min(newText.length, newText.length), extentOffset: math.min(newText.length, newText.length), ); return TextEditingValue( text: newText, selection: newSelection, composing: TextRange.empty, ); } return oldValue; } }
Комментарии:
1. Добро пожаловать в Stack Overflow и спасибо, что вернулись к вашему вопросу, чтобы поделиться своим решением с сообществом. Не могли бы вы, пожалуйста, отредактировать свой ответ, включив в него объяснение вашего кода? Это поможет будущим читателям лучше понять, что происходит, и особенно тем членам сообщества, которые новички в языке и изо всех сил пытаются понять концепции.