Время ввода флаттера в формате чч:мм:сс в текстовом поле или текстовом поле без использования средств выбора

#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 и спасибо, что вернулись к вашему вопросу, чтобы поделиться своим решением с сообществом. Не могли бы вы, пожалуйста, отредактировать свой ответ, включив в него объяснение вашего кода? Это поможет будущим читателям лучше понять, что происходит, и особенно тем членам сообщества, которые новички в языке и изо всех сил пытаются понять концепции.