Flutter数量输入插件input_quantity的使用

发布于 1周前 作者 htzhanglong 来自 Flutter

Flutter数量输入插件input_quantity的使用

Input Quantity

Flutter的数量输入插件input_quantity允许用户通过点击按钮来增加或减少输入值,同时也支持手动输入。此插件具有灵活配置输入限制、自定义外观和行为以及多种样式选项等功能。

Demo Preview

功能特性

  • 简单易用
  • 高度可定制
  • 支持输出类型:intdoublenum
  • 提供经典样式、按钮在左侧或右侧的样式
  • 支持点击更新值、长按连续更新值或手动输入值
  • 可添加表单验证或自定义消息构建器

安装

在您的pubspec.yaml文件中添加input_quantity作为依赖项:

dependencies:
  input_quantity: ^2.5.0

然后运行flutter pub get安装该包。

使用方法

基本用法

import 'package:input_quantity/input_quantity.dart';

InputQty(
  maxVal: 100,
  initVal: 0,
  minVal: -100,
  steps: 10,
  onQtyChanged: (val) {
    print(val);
  },
)

禁止手动输入

如果您希望阻止用户手动输入,可以禁用enableTyping属性:

InputQty(
  qtyFormProps: QtyFormProps(enableTyping: false),
  ...
)

指定输出类型

默认情况下,输出类型为num。要指定为intdouble,请使用InputQty.intInputQty.double构造函数:

// 输出类型为 int
InputQty.int(
  onQtyChanged: (val) {
    print(val.runtimeType); // int
  },
)

// 输出类型为 double
InputQty.double(
  onQtyChanged: (val) {
    print(val.runtimeType); // double
  },
)

自定义外观与行为

您可以使用QtyFormProps来自定义输入框的外观和行为,如文本对齐方式、字体样式、光标颜色等:

InputQty(
  qtyFormProps: QtyFormProps(
    textAlign: TextAlign.center,
    style: TextStyle(fontWeight: FontWeight.bold),
    cursorColor: Colors.red,
    enableTyping: true,
  ),
)

您还可以使用QtyDecorationProps来自定义输入框的装饰,如边框形状、按钮颜色、填充颜色等:

InputQty(
  decoration: QtyDecorationProps(
    borderShape: BorderShapeBtn.circle,
    btnColor: Colors.blue,
    fillColor: Colors.grey[200],
    isBordered: true,
  ),
)

表单验证

您可以通过validator属性对输入值进行验证:

InputQty(
  validator: (value) {
    if (value == null) {
      return "Required field";
    } else if (value >= 200) {
      return "More than available quantity";
    }
    return null;
  },
)

自定义消息

使用messageBuilder属性显示基于输入值的自定义消息:

InputQty(
  messageBuilder: (minVal, maxVal, value) {
    if (value == null) return null;
    if (value < -20) {
      return Text(
        "Reach my limit",
        style: TextStyle(color: Colors.red),
        textAlign: TextAlign.center,
      );
    } else if (value > 20) {
      return Text(
        "Reach my limit",
        style: TextStyle(color: Colors.red),
        textAlign: TextAlign.center,
      );
    } else {
      return Text("Value : $value", textAlign: TextAlign.center);
    }
  },
)

程序控制输入值

使用TextEditingController来程序化地控制输入值:

final TextEditingController _controller = TextEditingController();

InputQty(
  qtyFormProps: QtyFormProps(
    controller: _controller,
  ),
)

按钮方向

更改按钮的方向:

InputQty(
  decoration: QtyDecorationProps(
    orientation: ButtonOrientation.horizontal,
  ),
)

按钮位置

更改按钮的位置:

InputQty(
  decoration: QtyDecorationProps(
    qtyStyle: QtyStyle.btnOnRight,
  ),
)

示例代码

以下是一个完整的示例代码,展示了如何在项目中使用input_quantity插件:

import 'package:flutter/material.dart';
import 'package:input_quantity/input_quantity.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Input Quantity Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Input Quantity'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _formKey = GlobalKey<FormState>();
  final TextEditingController _controller = TextEditingController();

  int qtyInt = 123;
  double qtyDouble = 12.0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      body: SingleChildScrollView(
        child: Form(
          key: _formKey,
          child: Padding(
            padding: const EdgeInsets.all(20.0),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                const Padding(
                  padding: EdgeInsets.all(8.0),
                  child: Text(
                    'INPUT QUANTITY',
                    style: TextStyle(fontSize: 24, fontWeight: FontWeight.w500),
                  ),
                ),
                const Padding(
                  padding: EdgeInsets.all(14.0),
                  child: Text(
                    'by: pmatatias.dev',
                    style: TextStyle(fontSize: 14, color: Colors.blue),
                  ),
                ),
                const Divider(),
                const Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    InputQty(
                      maxVal: 50,
                      initVal: 10,
                      steps: 10,
                      minVal: -50,
                      qtyFormProps: QtyFormProps(enableTyping: false),
                      decoration: QtyDecorationProps(
                        isBordered: false,
                        minusBtn: Icon(
                          Icons.flight_land_rounded,
                          color: Colors.purple,
                        ),
                        plusBtn: Icon(Icons.flight_takeoff, color: Colors.indigo),
                      ),
                    ),
                    SizedBox(width: 30),
                    Expanded(
                      child: Text(
                          "- Output: int,double, num\n- initVal, maxVal, minVal, steps \n- Custom: icon,decoration,etc"),
                    )
                  ],
                ),
                const Divider(height: 30),
                const Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    InputQty(
                        decoration: QtyDecorationProps(
                            isBordered: false,
                            borderShape: BorderShapeBtn.circle,
                            width: 12)),
                    SizedBox(width: 30),
                    Expanded(
                        child: Text(
                            "- Ontap\n- Longpress \n- Typing input Manually"))
                  ],
                ),
                const Divider(),
                Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    InputQty(
                      qtyFormProps: QtyFormProps(
                        controller: _controller,
                      ),
                    ),
                    const SizedBox(width: 30),
                    const Expanded(
                      child: Text("use controller to get value (string)"),
                    )
                  ],
                ),
                const Divider(height: 50),
                InputQty(
                  maxVal: 100,
                  qtyFormProps: QtyFormProps(
                    controller: _controller,
                  ),
                ),
                Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: [
                    Column(
                      children: [
                        const Padding(
                            padding: EdgeInsets.all(8.0),
                            child: Text('Use validator')),
                        InputQty(
                          initVal: 0,
                          steps: 10,
                          minVal: -100,
                          maxVal: 100,
                          validator: (value) {
                            if (value == null) {
                              return "Required field";
                            } else if (value >= 200) {
                              return "More than available quantity";
                            }
                            return null;
                          },
                        ),
                      ],
                    ),
                    const Center(
                        child: Text(
                      "OR",
                      style: TextStyle(fontSize: 20, color: Colors.black),
                    )),
                    Column(
                      children: [
                        const Padding(
                          padding: EdgeInsets.only(bottom: 8.0),
                          child: Text(
                            'Message builder',
                          ),
                        ),
                        InputQty(
                          initVal: 0,
                          minVal: -100,
                          maxVal: 100,
                          steps: 2,
                          messageBuilder: (minVal, maxVal, value) {
                            if (value == null) return null;
                            if (value < -20) {
                              return const Text(
                                "Reach my limit",
                                style: TextStyle(color: Colors.red),
                                textAlign: TextAlign.center,
                              );
                            } else if (value > 20) {
                              return const Text(
                                "Reach my limit",
                                style: TextStyle(color: Colors.red),
                                textAlign: TextAlign.center,
                              );
                            } else {
                              return Text("Value : $value",
                                  textAlign: TextAlign.center);
                            }
                          },
                        ),
                      ],
                    ),
                  ],
                ),
                const Divider(height: 50),
                const Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: [
                    Column(
                      children: [
                        Padding(
                            padding: EdgeInsets.all(8.0),
                            child: Text('integer')),
                        InputQty.int(
                          initVal: 0,
                          steps: 10,
                          minVal: -100,
                        ),
                      ],
                    ),
                    Center(
                        child: Text(
                      "OR",
                      style: TextStyle(
                        fontSize: 20,
                        color: Colors.black,
                      ),
                    )),
                    Column(
                      children: [
                        Padding(
                          padding: EdgeInsets.all(8.0),
                          child: Text(
                            'double',
                          ),
                        ),
                        InputQty(
                          initVal: 0.0,
                          minVal: -100.0,
                          maxVal: 100.0,
                          steps: 0.1,
                        ),
                      ],
                    ),
                  ],
                ),
                const SizedBox(height: 30),
                const Divider(),

                const Text("Custom Border:"),
                const SizedBox(height: 12),
                ConstrainedBox(
                  constraints: const BoxConstraints(maxWidth: 200),
                  child: InputQty(
                    isIntrinsicWidth: false,
                    qtyFormProps: const QtyFormProps(),
                    decoration: QtyDecorationProps(
                        qtyStyle: QtyStyle.btnOnRight,
                        border: OutlineInputBorder(
                            borderSide:
                                const BorderSide(width: 5, color: Colors.green),
                            borderRadius: BorderRadius.circular(6)),
                        minusBtn: const Padding(
                          padding: EdgeInsets.symmetric(horizontal: 8.0),
                          child: Icon(Icons.keyboard_arrow_down_sharp,
                              color: Colors.blue),
                        ),
                        plusBtn: const Padding(
                          padding: EdgeInsets.symmetric(horizontal: 8.0),
                          child: Icon(
                            Icons.keyboard_arrow_up,
                            color: Colors.blue,
                          ),
                        )),
                    onQtyChanged: (val) {},
                  ),
                ),
                const Divider(height: 30),

                const Text("Style options:"),
                const SizedBox(height: 12),

                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: [
                    InputQty.int(
                      messageBuilder: (minVal, maxVal, value) =>
                          const Text("Button on Left", textAlign: TextAlign.center),
                      decoration: const QtyDecorationProps(
                          qtyStyle: QtyStyle.btnOnLeft,
                          width: 12,
                          fillColor: Colors.black12,
                          isBordered: false,
                          borderShape: BorderShapeBtn.square),
                    ),
                    InputQty.int(
                      messageBuilder: (minVal, maxVal, value) =>
                          const Text("Button on Right", textAlign: TextAlign.center),
                      qtyFormProps: const QtyFormProps(cursorColor: Colors.amber),
                      decoration: const QtyDecorationProps(
                          qtyStyle: QtyStyle.btnOnRight,
                          width: 12,
                          fillColor: Colors.black12,
                          isBordered: false,
                          borderShape: BorderShapeBtn.square),
                    ),
                  ],
                ),
                const SizedBox(height: 30),
                InputQty.int(
                  messageBuilder: (minVal, maxVal, value) =>
                      const Text("Classic", textAlign: TextAlign.center),
                  decoration: const QtyDecorationProps(
                      qtyStyle: QtyStyle.classic,
                      width: 12,
                      fillColor: Colors.black12,
                      isBordered: false,
                      borderShape: BorderShapeBtn.none),
                ),
                const SizedBox(height: 30),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: [
                    InputQty.int(
                      messageBuilder: (minVal, maxVal, value) =>
                          const Text("Button on Right Horizontal", textAlign: TextAlign.center),
                      qtyFormProps: const QtyFormProps(cursorColor: Colors.amber),
                      decoration: const QtyDecorationProps(
                          qtyStyle: QtyStyle.btnOnLeft,
                          width: 12,
                          orientation: ButtonOrientation.horizontal,
                          isBordered: false,
                          borderShape: BorderShapeBtn.square),
                    ),
                    InputQty.int(
                      messageBuilder: (minVal, maxVal, value) =>
                          const Text("Button on Right Horizontal", textAlign: TextAlign.center),
                      qtyFormProps: const QtyFormProps(cursorColor: Colors.amber),
                      decoration: const QtyDecorationProps(
                          qtyStyle: QtyStyle.btnOnRight,
                          width: 12,
                          orientation: ButtonOrientation.horizontal,
                          isBordered: false,
                          borderShape: BorderShapeBtn.square),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

以上是关于input_quantity插件的详细说明和完整示例代码,希望能够帮助您更好地理解和使用这个插件。如果您有任何问题或需要进一步的帮助,请随时提问!


更多关于Flutter数量输入插件input_quantity的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter数量输入插件input_quantity的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,我可以为你提供一个关于如何在Flutter项目中使用input_quantity插件的示例代码。input_quantity是一个用于数量输入的Flutter插件,它允许用户通过滑动或点击来增加或减少数量。

首先,你需要在你的pubspec.yaml文件中添加这个插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  input_quantity: ^x.y.z  # 请替换为最新版本号

然后运行flutter pub get来获取依赖。

接下来,在你的Flutter项目中,你可以按照以下方式使用这个插件:

import 'package:flutter/material.dart';
import 'package:input_quantity/input_quantity.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: QuantityInputScreen(),
    );
  }
}

class QuantityInputScreen extends StatefulWidget {
  @override
  _QuantityInputScreenState createState() => _QuantityInputScreenState();
}

class _QuantityInputScreenState extends State<QuantityInputScreen> {
  int _quantity = 1;

  void _onQuantityChanged(int quantity) {
    setState(() {
      _quantity = quantity;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Quantity Input Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Selected Quantity: $_quantity'),
            SizedBox(height: 20),
            QuantityInput(
              initialValue: _quantity,
              minValue: 1,
              maxValue: 100,
              step: 1,
              onQuantityChanged: _onQuantityChanged,
              decoration: InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Quantity',
                suffixIcon: Icon(Icons.arrow_drop_down),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

代码解释:

  1. 依赖导入

    import 'package:input_quantity/input_quantity.dart';
    
  2. 主应用结构

    • MyApp是一个无状态小部件,它包含了一个MaterialApp,并设置了主题和主页面。
    • QuantityInputScreen是一个有状态小部件,用于管理数量输入的状态。
  3. 状态管理

    • 使用_quantity变量来存储当前的数量。
    • 使用_onQuantityChanged方法来更新数量。
  4. UI布局

    • 使用Scaffold来创建页面的基本结构。
    • body中,使用CenterColumn来排列文本和数量输入控件。
    • QuantityInput控件用于数量输入,设置初始值、最小值、最大值、步长以及数量变化时的回调函数。

这个示例展示了如何在Flutter中使用input_quantity插件来创建一个简单的数量输入界面。你可以根据需要调整最小值、最大值、步长和其他参数。

回到顶部