Flutter文本表单验证插件textformfield_unit的使用

Flutter 文本表单验证插件 textformfield_unit 的使用

概述

TextFormField 小部件带有一个下拉列表用于单位选择,并提供转换功能。

使用方法

你可以几乎像使用原始的 TextFormField 一样来使用它,但需要添加一些额外的功能。

首先,它有一个泛型类型,即你想要使用的单位类型。假设我们需要以下三个长度单位:

enum SizeUnits { Millimeter, Inch, LightNanosecond }

我们准备一个映射,包含用户可读的名称:

static final unitNames = {
  SizeUnits.Millimeter: 'mm',
  SizeUnits.Inch: '"',
  SizeUnits.LightNanosecond: 'light-ns',
};

还需要一个函数,该函数可以接收一个值并将其从一种单位转换为另一种单位:

double _sizeConverter(SizeUnits fromUnit, SizeUnits toUnit, double value) {
  final valueMm = switch (fromUnit) {
    SizeUnits.Millimeter => value,
    SizeUnits.Inch => value * 25.4,
    SizeUnits.LightNanosecond => value * 299.792458,
  };
  return switch (toUnit) {
    SizeUnits.Millimeter => valueMm,
    SizeUnits.Inch => valueMm / 25.4,
    SizeUnits.LightNanosecond => valueMm / 299.792458,
  };
}

我们将这些参数(以及其他任何通常的 TextFormField 参数)传递给字段:

TextFormUnitField<SizeUnits>(
  controller: controller,
  keyboardType: TextInputType.number,
  inputFormatters: [FilteringTextInputFormatter.allow(allowed)],
  textInputAction: TextInputAction.next,
  icon: const Icon(Icons.height),
  labelText: 'Size',
  units: unitNames,
  initialUnit: SizeUnits.Millimeter,
  unitIcon: const Icon(Icons.keyboard_arrow_down),
  converter: _sizeConverter,
  onSaved: (value) {
    if (value != null) print('${value.value} ${unitNames[value.unit]}');
  },
),

当它调用回调进行验证或保存时,它会传递一个 ValueWithUnit<T> 类型的值,其中 T 是我们的单位类型。

完整示例

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'package:textformfield_unit/textformfield_unit.dart';

enum SizeUnits { Millimeter, Inch, LightNanosecond, Twip, Thou, Barleycorn, Foot, Yard, Chain, Furlong, Mile, League, Fathom, NauticalMile, Link, Rod }

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'TextFormFieldUnit Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  static final unitNames = {
    SizeUnits.Millimeter: 'mm',
    SizeUnits.Inch: 'in',
    SizeUnits.LightNanosecond: 'light-ns',
    SizeUnits.Twip: 'twip',
    SizeUnits.Thou: 'th',
    SizeUnits.Barleycorn: 'Bc',
    SizeUnits.Foot: 'ft',
    SizeUnits.Yard: 'yd',
    SizeUnits.Chain: 'ch',
    SizeUnits.Furlong: 'fur',
    SizeUnits.Mile: 'mi',
    SizeUnits.League: 'lea',
    SizeUnits.Fathom: 'ftm',
    SizeUnits.NauticalMile: 'nmi',
    SizeUnits.Link: 'links',
    SizeUnits.Rod: 'rods',
  };
  final formKey = GlobalKey<FormState>();
  late TextEditingController controller;

  [@override](/user/override)
  void initState() {
    super.initState();
    controller = TextEditingController(text: NumberFormat.decimalPattern().format(156.25));
  }

  [@override](/user/override)
  void dispose() {
    super.dispose();
    controller.dispose();
  }

  double _sizeConverter(SizeUnits fromUnit, SizeUnits toUnit, double value) {
    final valueMm = switch (fromUnit) {
      SizeUnits.Millimeter => value,
      SizeUnits.Inch => value * 25.4,
      SizeUnits.LightNanosecond => value * 299.792458,
      SizeUnits.Twip => value * 0.0176389,
      SizeUnits.Thou => value * 0.0254,
      SizeUnits.Barleycorn => value * 8.4667,
      SizeUnits.Foot => value * 0304.8,
      SizeUnits.Yard => value * 914.4,
      SizeUnits.Chain => value * 20116.8,
      SizeUnits.Furlong => value * 201168,
      SizeUnits.Mile => value * 1609344,
      SizeUnits.League => value * 4828032,
      SizeUnits.Fathom => value * 1852,
      SizeUnits.NauticalMile => value * 1852,
      SizeUnits.Link => value * 0201.168,
      SizeUnits.Rod => value * 5029.2,
    };
    return switch (toUnit) {
      SizeUnits.Millimeter => valueMm,
      SizeUnits.Inch => valueMm / 25.4,
      SizeUnits.LightNanosecond => valueMm / 299.792458,
      SizeUnits.Twip => valueMm / 0.0176389,
      SizeUnits.Thou => valueMm / 0.0254,
      SizeUnits.Barleycorn => valueMm / 8.4667,
      SizeUnits.Foot => valueMm / 0304.8,
      SizeUnits.Yard => valueMm / 914.4,
      SizeUnits.Chain => valueMm / 20116.8,
      SizeUnits.Furlong => valueMm / 201168,
      SizeUnits.Mile => valueMm / 1609344,
      SizeUnits.League => valueMm / 4828032,
      SizeUnits.Fathom => valueMm / 1852,
      SizeUnits.NauticalMile => valueMm / 1852,
      SizeUnits.Link => valueMm / 0201.168,
      SizeUnits.Rod => valueMm / 5029.2,
    };
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    final allowed = switch (NumberFormat().symbols.DECIMAL_SEP) {
      '.' => RegExp(r'[\d.]'),
      ',' => RegExp(r'[\d,]'),
      _ => RegExp(r'\d'),
    };

    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Form(
                key: formKey,
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    TextFormUnitField<SizeUnits>(
                      controller: controller,
                      keyboardType: TextInputType.number,
                      inputFormatters: [FilteringTextInputFormatter.allow(allowed)],
                      textInputAction: TextInputAction.next,
                      icon: const Icon(Icons.height),
                      labelText: 'Size',
                      units: unitNames,
                      initialUnit: SizeUnits.Millimeter,
                      unitIcon: const Icon(Icons.keyboard_arrow_down),
                      converter: _sizeConverter,
                      onSaved: (value) {
                        if (value != null) print('${value.value} ${unitNames[value.unit]}');
                      },
                    ),
                  ],
                )),
            ElevatedButton(
              onPressed: () {
                if (formKey.currentState!.validate()) {
                  formKey.currentState!.save();
                }
              },
              child: const Text('Save'),
            ),
          ],
        ),
      ),
    );
  }
}

更多关于Flutter文本表单验证插件textformfield_unit的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter文本表单验证插件textformfield_unit的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


TextFormField 是 Flutter 中用于构建表单输入字段的常用小部件。它允许你轻松地验证用户输入,并提供反馈以帮助用户正确填写表单。虽然 Flutter 本身并没有名为 textformfield_unit 的插件,但你可以通过自定义 TextFormField 来实现各种验证功能。

以下是一个简单的示例,展示了如何使用 TextFormField 进行基本的文本验证:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('TextFormField Validation Example'),
        ),
        body: MyCustomForm(),
      ),
    );
  }
}

class MyCustomForm extends StatefulWidget {
  [@override](/user/override)
  _MyCustomFormState createState() => _MyCustomFormState();
}

class _MyCustomFormState extends State<MyCustomForm> {
  final _formKey = GlobalKey<FormState>();

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          TextFormField(
            decoration: InputDecoration(
              labelText: 'Enter your email',
            ),
            validator: (value) {
              if (value == null || value.isEmpty) {
                return 'Please enter some text';
              }
              if (!RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+")
                  .hasMatch(value)) {
                return 'Please enter a valid email address';
              }
              return null;
            },
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 16.0),
            child: ElevatedButton(
              onPressed: () {
                // Validate returns true if the form is valid, or false otherwise.
                if (_formKey.currentState!.validate()) {
                  // If the form is valid, display a snackbar. In the real world,
                  // you'd often call a server or save the information in a database.
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(content: Text('Processing Data')),
                  );
                }
              },
              child: Text('Submit'),
            ),
          ),
        ],
      ),
    );
  }
}
回到顶部