regex 在TextFormField或TextField中不使用拾取器以hh:mm:ss格式抖动输入时间

rseugnpd  于 2023-10-22  发布在  其他
关注(0)|答案(5)|浏览(107)

有没有人可以帮助弄清楚如何设置一个文本字段或文本表单字段小部件的时间输入在hh:mm:ss格式?
格式应该在字段中实时显示,因此在用户键入时前导零将被替换。
例如,如果我们需要输入1 hour 59 minutes and 27 seconds,它需要如下工作:

  • 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() => _TimeInputFieldState();
}

class _TimeInputFieldState extends State<TimeInputField> {
  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: <TextInputFormatter>[
        timeMaskFormatter
        // Not sure if it can be done with RegExp or a custom class here instead
      ],
    );
  }
}

任何帮助都非常感谢!

qvtsj1bj

qvtsj1bj1#

我在文本字段中使用了TextInputFormatter而不是onChanged。这允许访问旧值并根据新字符是添加还是删除来格式化新输入。它还允许使用RegExp只接受数字。这将是解决方案:

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() => _TimeInputFieldState();
}

class _TimeInputFieldState extends State<TimeInputField> {
  TextEditingController _txtTimeController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      controller: _txtTimeController,
      keyboardType: TextInputType.numberWithOptions(decimal: false),
      decoration: InputDecoration(
        hintText: '00:00:00',
      ),
      inputFormatters: <TextInputFormatter>[
        TimeTextInputFormatter() // This input formatter will do the job        
      ],
    );
  }
}

class TimeTextInputFormatter extends TextInputFormatter {
  RegExp _exp;
  TimeTextInputFormatter() {
    _exp = RegExp(r'^[0-9:]+$');
  }

  @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 >= 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 && oldValue.text.substring(0, 1) != '0') {
        if (value.length > 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;
  }
}
kxeu7u2r

kxeu7u2r2#

我还使用了文本输入法来避免太多的if

import 'package:flutter/services.dart';
import 'dart:math' as math;

class HourMinsFormatter extends TextInputFormatter {
  late RegExp pattern;
  HourMinsFormatter() {
    pattern = RegExp(r'^[0-9:]+$');
  }

  String pack(String value) {
    if (value.length != 4) return value;
    return value.substring(0, 2) + ':' + value.substring(2, 4);
  }

  String unpack(String value) {
    return value.replaceAll(':', '');
  }

  String complete(String value) {
    if (value.length >= 4) return value;
    final multiplier = 4 - value.length;
    return ('0' * multiplier) + value;
  }

  String limit(String value) {
    if (value.length <= 4) return value;
    return value.substring(value.length - 4, value.length);
  }

  @override
  TextEditingValue formatEditUpdate(
    TextEditingValue oldValue,
    TextEditingValue newValue,
  ) {
    if (!pattern.hasMatch(newValue.text)) return oldValue;

    TextSelection newSelection = newValue.selection;

    String toRender;
    String newText = newValue.text;

    toRender = '';
    if (newText.length < 5) {
      if (newText == '00:0')
        toRender = '';
      else
        toRender = pack(complete(unpack(newText)));
    } else if (newText.length == 6) {
      toRender = pack(limit(unpack(newText)));
    }

    newSelection = newValue.selection.copyWith(
      baseOffset: math.min(toRender.length, toRender.length),
      extentOffset: math.min(toRender.length, toRender.length),
    );

    return TextEditingValue(
      text: toRender,
      selection: newSelection,
      composing: TextRange.empty,
    );
  }
}
4dbbbstv

4dbbbstv3#

在TextFormField或TextField中使用hh:mm格式的抖动时间输入格式化程序,不使用拾取器,具有最大小时数和最大分钟数:

import 'dart:math' as math;

import 'package:flutter/services.dart';

class TimeTextInputFormatter extends TextInputFormatter {
  TimeTextInputFormatter(
      {required this.hourMaxValue, required this.minuteMaxValue}) {
    _exp = RegExp(r'^$|[0-9:]+$');
  }
  late RegExp _exp;

  final int hourMaxValue;
  final int minuteMaxValue;
  @override
  TextEditingValue formatEditUpdate(
    TextEditingValue oldValue,
    TextEditingValue newValue,
  ) {
    if (_exp.hasMatch(newValue.text)) {
    TextSelection newSelection = newValue.selection;

    final String value = newValue.text;
    String newText;

    String leftChunk = '';
    String rightChunk = '';

    if (value.length > 1 &&
        (int.tryParse(value.substring(0, 2)) ?? 0) == hourMaxValue)
    //this logic is to restrict value more than max hour
    {
      if (oldValue.text.contains(':')) {
        leftChunk = value.substring(0, 1);
      } else {
        leftChunk = '${value.substring(0, 2)}:';
        rightChunk = '00';
      }
    } else if (value.length > 5) {
      //this logic is to not allow more value
      leftChunk = oldValue.text;
    } else if (value.length == 5) {
      if ((int.tryParse(value.substring(3)) ?? 0) > minuteMaxValue) {
        //this logic is to restrict value more than max minute
        leftChunk = oldValue.text;
      } else {
        leftChunk = value;
      }
    } else if (value.length == 2) {
      if (oldValue.text.contains(':')) {
        //this logic is to delete : & value before : ,when backspacing
        leftChunk = value.substring(0, 1);
      } else {
        if ((int.tryParse(value) ?? 0) > hourMaxValue) {
          //this logic is to restrict value more than max hour
          leftChunk = oldValue.text;
        } else {
          //this logic is to add : with second letter
          leftChunk = '${value.substring(0, 2)}:';
          rightChunk = value.substring(2);
        }
      }
    } else {
      leftChunk = value;
    }
    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,
    ); }
    return oldValue;
  }
}
jpfvwuh4

jpfvwuh44#

更新代码:

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() => _TimeInputFieldState();
}

class _TimeInputFieldState extends State<TimeInputField> {
  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;i<=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;

                    }
                  },
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
ubbxdtey

ubbxdtey5#

我有非常简单的逻辑来解决时间问题

final localizations = MaterialLocalizations
                                      .of(context);
                                  final formattedTimeOfDay = localizations
                                      .formatTimeOfDay(time!);
                                  switch(int.parse(formattedTimeOfDay.split(":")[0])<=9){
                                    case true:
                                      timeController.text = "0"+formattedTimeOfDay;
                                      break;
                                    case false:
                                      timeController.text = formattedTimeOfDay;
                                      break;
                                  }

试用看看

相关问题