Material & Cupertino SpinBox for Flutter

Overview

SpinBox for Flutter

pub score build codecov style: lint license: MIT

SpinBox for Flutter is a numeric input widget with an input field for entering a specific value, and spin buttons for quick, convenient, and accurate value adjustments.

SpinBox for Flutter comes in two variants. It provides implementations for both designs in Flutter, Material and Cupertino (iOS).

Material Design

SpinBox

import 'package:flutter_spinbox/material.dart'; // or flutter_spinbox.dart for both

SpinBox(
  min: 1,
  max: 100,
  value: 50,
  onChanged: (value) => print(value),
)

See also Material Components widgets package.

Cupertino (iOS-style) Design

CupertinoSpinBox

import 'package:flutter_spinbox/cupertino.dart'; // or flutter_spinbox.dart for both

CupertinoSpinBox(
  min: 1,
  max: 100,
  value: 50,
  onChanged: (value) => print(value),
)

See also Cupertino (iOS-style) widgets package.

Guidelines

Spin boxes are best suited for such applications

  • that deal with large numeric value ranges and high precisions,
  • where users typically know upfront the exact value they are entering,
  • where users may later have a need to accurately adjust a previously entered value.

As a rule of thumb, spin boxes are great for scenarios where

  • sliders and alike UI controls are too inaccurate,
  • tumblers and alike UI controls cannot provide enough value range,
  • and a plain text field is inconvenient for value adjustments (open the VKB, move the cursor, erase the previous value, enter a new value... vs. tap-tap-done).

Usage

To use this package, add flutter_spinbox as a dependency in your pubspec.yaml file.

Comments
  • Unable to enter decimals via keyboard on Android

    Unable to enter decimals via keyboard on Android

    I'm using SpinBox within a component like so:

    SpinBox(
      value: _value!.toDouble(),
      min: widget.min,
      max: widget.max,
      step: widget.step,
      decimals: widget.decimals,
      keyboardType: TextInputType.numberWithOptions(decimal: true),
      onChanged: (newValue) {
        setState(() {
          _value = newValue;
        });
        widget.onChanged?.call(newValue);
    })
    

    But when I pop the keyboard and enter (e.g.) 6.0 it appears in the spinner as 60 (i.e. the decimal key is ignored) and I have to manually select the decimal part of the number to replace it.

    This happens both with and without the manually set keyboardType, which I think shouldn't be necessary as widget.decimals is greater than zero.

    Am I missing something obvious? I didn't see anything other than keyboardType in the API docs but apologies if I have!

    opened by jamiecollinson 5
  • CupertinoSpinBox initialValue not resetting

    CupertinoSpinBox initialValue not resetting

    Good day, I'm using 2 cupertinospinboxs. Both allow for individual "spins". When the 1st spinner is set to 0 (zero), the 2nd widget is expected to be reset to 0 as well. The underlaying data source is managed by Provider and ChangeNotifier. I console print out the value of initialValue for both spinners and see that the initial build is correct for both initialValues. When the 1st spinner is set to 0, the console print shows the 2nd spinner's initialValue is the expected 0 value but the displayed value remains at the current value, ie not getting reset. Not sure if this is an issue specific to your script so Im still researching for a solution but was hoping you may have a solution/correction or workaround. Thank you for your time.

    opened by soccerjf 4
  • Option to use theme colour when not focused

    Option to use theme colour when not focused

    When the SpinBox is not focused the button colour defaults to grey, clicking inside the textfield will focus the widget and change the buttons colours to use the theme colours. Is the a possibility of adding an option to always use theme colours when enabled? unfocused Screenshot 2021-04-22 113546

    focused Screenshot 2021-04-22 113442 Screenshot 2021-04-22 113609

    Thanks

    opened by ConcenTech 3
  • Add a callbacks like 'CanChange'

    Add a callbacks like 'CanChange'

    I need to validate using some rules if the new value can be accepted before changed.

    Would be nice to have callbacks like: beforeIncrement. beforeDecrement, canChangeValue...

    Thank you!

    opened by daybson 3
  • Expose readOnly TextField property

    Expose readOnly TextField property

    I made a simple PR to expose the readOnly property to avoid keyboard in some ocasions. i hope you like! Best Regards!

    
    SpinBox(
      min: 1,
      max: 20,
      value: 1,
      readOnly:true,
      onChanged: (value) => print(value),
    )
    opened by brasizza 2
  • SpinBox children of a stateful widget do not update

    SpinBox children of a stateful widget do not update

    Hello, I'm currently trying this plugin since it looks good for my needs.

    I have a parent StatefulWidget with two integer values, two callbacks for updating both of them and calling setState every time I increment or decrement the value but just the spinbox that is manipulated updates, the other one stays the same, while I'd expect both of them to update since I'm rebuilding the parent widget.

    I'm currently using Flutter 2.2.3 (but it happened also in 2.2.2), flutter_spinbox 0.5.2 and I'm on Windows. To reproduce the issue, just create a new Flutter project and replace class _MyHomePageState with the following code:

    class _MyHomePageState extends State<MyHomePage> {
      int _counter1 = 0;
      int _counter2 = 10;
    
      void _changeCounter1(final int newVal) {
        setState(() {
          _counter1 = newVal;
          _counter2 = newVal % 10;
        });
      }
    
      void _changeCounter2(final int newVal) {
        setState(() {
          _counter1 = newVal % 10;
          _counter2 = newVal;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        print('rebuild with counter 1: $_counter1 and counter 2: $_counter2');
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                SpinBox(
                  step: 1,
                  decimals: 0,
                  onChanged: (val) => _changeCounter1(val.toInt()),
                  value: _counter1.toDouble(),
                  min: 0,
                  max: 100,
                ),
                SpinBox(
                  step: 1,
                  decimals: 0,
                  onChanged: (val) => _changeCounter2(val.toInt()),
                  value: _counter2.toDouble(),
                  min: 0,
                  max: 100,
                ),
              ],
            ),
          ),
        );
      }
    }
    

    The two values, _counter1 and _counter2 update, the spinboxes don't.

    The example is super dummy, I do not care which value actually are present in the spinbox right now, I want just them to update.

    I'd really appreciate to understand what is the problem, if I'm doing something wrong or what. Thanks!

    opened by TommasoAzz 2
  • Use theme color when enabled but not focused. Closes jpnurmi/flutter_spinbox#26

    Use theme color when enabled but not focused. Closes jpnurmi/flutter_spinbox#26

    I've added the bool paintWhenEnabled, if anyone wants to keep the default behaviour they can set this to false, otherwise leaving as true will paint the buttons and TextField underline with _activeColor() when enabled, regardless if it is focused or not.

    I've removed if (hasFocus) from _activeColor as the only call to _activeColor was already inside an if (hasFocus)

    This then allows me to use _activeColor when enabled.

    opened by ConcenTech 2
  • Doesn't compile with latest SDK

    Doesn't compile with latest SDK

    See below error...

    ../../../FlutterSDK/.pub-cache/hosted/pub.dartlang.org/flutter_spinbox-0.5.0/lib/src/base_spin_box.dart:68:52: Error: A value of type 'bool' can't be returned from a function with return type 'KeyEventResult'.
     - 'KeyEventResult' is from 'package:flutter/src/widgets/focus_manager.dart' ('../../../FlutterSDK/packages/flutter/lib/src/widgets/focus_manager.dart').
        _focusNode = FocusNode(onKey: (node, event) => _handleKey(event));
    
    opened by wayneprice 2
  • Assert issue when starting from negative value

    Assert issue when starting from negative value

    Hello, First of, thank you for your package!

    My issue is that whenever I increment to negative value to 0 (-1 -> 0/ -0.1 -> 0.0) I get this exception:

    The following assertion was thrown while handling a gesture:
    Assertion failed: org-dartlang-sdk:///flutter_web_sdk/lib/ui/src/ui/text.dart:458:16
    start != null && start >= -1
    is not true
    

    This is how I initialise the object:

    SpinBox(
    spacing: 0,
    min: min,
    max: max,
    step: step,
    value: value,
    decimals: decimals,
    onChanged: onChanged,
    )
    

    Example of how I use it:

    _spinbox(
    label: "Max stock",
    min: -1,
    value: _maxStock,
    onChanged: (val) => context.read<ReportsGeneratorCubit>().updateStock(max: val),
    ),
    

    The issue seem to happen if the field isn't focused. Any ideea how I can solve it?

    opened by vadrian89 2
  • Can't submit 2 digits values by keyboard when using key: UniqueKey()

    Can't submit 2 digits values by keyboard when using key: UniqueKey()

    Hi,I need to set the value programmatically so I used 'key' as here: https://github.com/jpnurmi/flutter_spinbox/issues/16

    bun now I can't submit 2 digits values by keyboard, after first key pressed that hides,removing the key seems to work but I can't update the value thanks

    class _CantWdState extends State<CantWd> {
      @override
      Widget build(BuildContext context) {
        final prvCant = Provider.of<Cant>(context, listen: true);
        return Container(
          child: Row(
            children: <Widget>[
              Container(
                width: 125,
                child: SpinBox(
                  key: UniqueKey(), // here
                  min: 1,
                  max: 100,
                  step: 1,
                  value: prvCant.cant,
                  spacing: 24,
                  direction: Axis.horizontal,
                  textStyle: TextStyle(fontSize: 18, color: Colors.white),
                  incrementIcon:
                      Icon(Icons.keyboard_arrow_up, size: 25, color: Colors.white),
                  decrementIcon: Icon(
                    Icons.keyboard_arrow_down,
                    size: 25,
                    color: Colors.white,
                  ),
                  onChanged: (newValue) => prvCant.cant = newValue,
                ),
              ),
            ],
          ),
        );
      }
    }
    
    
    opened by mrjohnr 2
  • How to programmatically update the

    How to programmatically update the "value"?

    Is there a way to update the "value" programmable? For example

    class _HomeElementState extends State<HomeElement> {
      double years = 20;
    
      @override
      Widget build(BuildContext context) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            SpinBox(
              decoration: InputDecoration(labelText: "Years"),
              value: years,
              onChanged: (v) => setState(() => years = v),
            ),
            SpinBox(
              decoration: InputDecoration(labelText: "Born in"),
              max: DateTime.now().year.toDouble(),
              value: DateTime.now().year - years,
              onChanged: (v) => setState(() => years = DateTime.now().year - v),
            ),
            Text("Years: " + years.toString()),
            Text("Born in: " + (DateTime.now().year - years).toString())
          ],
        );
      }
    }
    
    opened by PavlMais 2
  • [propose] onSubmitted can be called when TextField loses focus and Spinbox is enabled.

    [propose] onSubmitted can be called when TextField loses focus and Spinbox is enabled.

    This behavior is very like valueModified of SpinBox in Qt Quick Control.

      void _handleFocusChanged() {
        setState(() {
          if (hasFocus) {
            _selectAll();
          } else {
            if (widget.enabled) {
              final value = fixupValue(_controller.text);
              widget.onSubmitted?.call(value);
            }
          }
        });
      }
    
    opened by zhang-peter 0
  • Dependency Dashboard

    Dependency Dashboard

    This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

    This repository currently has no open or pending branches.

    Detected dependencies

    github-actions
    .github/workflows/analyze.yml
    • actions/checkout v3
    • subosito/flutter-action v2
    • actions/checkout v3
    • subosito/flutter-action v2
    • actions/checkout v3
    • subosito/flutter-action v2
    .github/workflows/build.yml
    • actions/checkout v3
    • subosito/flutter-action v2
    • actions/checkout v3
    • subosito/flutter-action v2
    • actions/checkout v3
    • subosito/flutter-action v2
    • actions/checkout v3
    • subosito/flutter-action v2
    • actions/checkout v3
    • subosito/flutter-action v2
    • actions/checkout v3
    • subosito/flutter-action v2
    .github/workflows/test.yml
    • actions/checkout v3
    • subosito/flutter-action v2
    • actions/checkout v3
    • subosito/flutter-action v2
    • codecov/codecov-action v3
    pub
    example/pubspec.yaml
    pubspec.yaml
    • cupertino_icons ^1.0.2
    • lint ^2.0.0

    • [ ] Check this box to trigger a request for Renovate to run again on this repository
    opened by renovate[bot] 0
  • Feature request, to skip ranges of number

    Feature request, to skip ranges of number

    Is it possible to add a feature that skips ranges of number? let's say if I click + on 0 it will skip to 30 but if I click + on 30 it will increment like usual, and vice versa when I click - on 30 it will skip to 0

    opened by sandysultan 0
  • Validation inside a Form Widget

    Validation inside a Form Widget

    Hi @jpnurmi ; Tnx for this wonderful package ; I have a question ; how to validate SpinBox inside a FormWidget by formKey ? for example after that a button pressed ;

    opened by MohoCoder1997 0
  • Number shown is invalid if the range is externally limited

    Number shown is invalid if the range is externally limited

    The attached code demonstrates a bug with the spinbox. The spinbox itself is limited to a range of 2.0 to 4.0. The value starts at 3.0. However the onChanged callback limits the value to a range of 2.5 to 3.5. If you push the "+" button 6 times, the spinbox will display 3.6 even though the value given to it is limited to 3.5

    Screenshot_1648907584

    // ignore_for_file: avoid_print
    
    import 'package:flutter/material.dart';
    import 'package:flutter_spinbox/material.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: 'SpinBox Bug Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const MyHomePage(title: 'SpinBox Bug'),
        );
      }
    }
    
    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> {
      double value = 3.0;
      @override
      Widget build(BuildContext context) {
        print('value = $value');
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
            child: Column(
              children: [
                const Padding(
                  padding: EdgeInsets.all(8.0),
                  child: Text(
                    'The Value resets to 3.0.\n\nIf you push the plus key 6 times\n the number shown will advance to 3.6\neven though the value being assigned is limited to 3.5',
                    textAlign: TextAlign.center,
                  ),
                ),
                SpinBox(
                  value: value,
                  min: 2.0,
                  max: 4.0,
                  decimals: 1,
                  step: 0.1,
                  onChanged: (newValue) {
                    setState(() {
                      if (newValue <= 3.5 && newValue >= 2.5) {
                        value = newValue;
                      }
                      print('newValue = $newValue, value = $value');
                    });
                  },
                ),
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Text('Value = $value'),
                ),
                ElevatedButton(
                  child: const Text('RESET'),
                  onPressed: () {
                    setState(() {
                      value = 3.0;
                    });
                  },
                )
              ],
            ),
          ),
        );
      }
    }
    
    opened by dedvalson 3
Owner
J-P Nurmi
Flutter & Ubuntu
J-P Nurmi
Cupertino version of the Material Stepper in Flutter

Cupertino Stepper for Flutter Cupertino version of the stock Material Stepper in Flutter. NOTE: This is not the same as the UIStepper control on iOS.

J-P Nurmi 18 Oct 13, 2022
Target the specific design of Material for Android and Cupertino for iOS widgets through a common set of Platform aware widgets

Flutter Platform Widgets This project is an attempt to see if it is possible to create widgets that are platform aware. Currently in order to render t

null 1.3k Jan 4, 2023
Target the specific design of Material for Android and Cupertino for iOS widgets through a common set of Platform aware widgets

Flutter Platform Widgets This project is an attempt to see if it is possible to create widgets that are platform aware. Currently in order to render t

null 1.3k Jan 4, 2023
A Very Flexible Widget that can Implement Material Sheets on all Directions, both modal and persistent, and consequently a Material Navigation Drawer

Flutter_MaterialSheetAndNavigationDrawer If this project helped you reduce developement time or you just want to help me continue making useful tools

Bryan Cancel 30 Dec 4, 2021
Material io ext - A collection of extensions for creating widgets following material.io guidelines

material_io_ext It is a collection of extensions for creating widgets following

BetterX.io 3 Jan 28, 2022
A flutter date time picker inspired by flutter-cupertino-date-picker

Flutter Datetime Picker (Pub) flutter_datetime_picker A flutter date time picker inspired by flutter-cupertino-date-picker you can choose date / time

null 0 Nov 30, 2021
Flutter cupertino style date picker.

Flutter Cupertino Date Picker [pub packages] | 中文说明 Flutter cupertino date picker. Usage 1. Depend Add this to you package's pubspec.yaml file: depend

Dylan Wu 333 Dec 26, 2022
Flutter cupertino style date picker.

Flutter Cupertino Date Picker [pub packages] | 中文说明 Flutter cupertino date picker. Usage 1. Depend Add this to you package's pubspec.yaml file: depend

Dylan Wu 333 Dec 26, 2022
Cupertino back gesture - Flutter package to set custom width of iOS back swipe gesture area

cupertino_back_gesture A Flutter package to set custom width of iOS back swipe gesture area. Usage To use this package, add cupertino_back_gesture as

null 28 Dec 7, 2022
Flutter Cupertino text box which can be used to select a date with CupertinoDatePicker

Flutter Cupertino Date Text Box A text box with an attached CupertinoDatePicker which opens when the text box is tapped. With this library the followi

Christoph Rothermel 5 Feb 13, 2022
Flutter-sorted-chips-row - Flutter library for rendering a row of Material "Chip" buttons that gets sorted according to the given function

sorted_chips_row A Flutter Widget displaying a row of Material Chips, sorted according to the provided comparison function. How to use Adding dependen

Callstack Incubator 29 Jul 29, 2021
A Flutter material theme editor

Flutter Theme ⚠️ WARNING: This app is still under development so please expect bugs and missing features in the app. ⚠️ Inspired by Panache, a Flutter

null 0 Jan 2, 2022
A Flutter color palette with eyedropper, HSL, RGB and Material colors

Cyclop A flutter colorpicker with an eyedropper tool. Works on mobile, desktop & web ( CanvasKit) Demo Desktop & tablet Mobile Material HSL RVB Custom

Erick Ghaumez 106 Oct 17, 2022
🎨 Flutter Material Theme editor

?? Panache A Flutter Material Theme editor. Panache helps you to create beautiful Material themes for your Flutter applications. Customize widgets col

Erick Ghaumez 1.7k Dec 30, 2022
A Flutter color palette with eyedropper, HSL, RGB and Material colors

Cyclop A flutter colorpicker with an eyedropper tool. Works on mobile, desktop & web ( CanvasKit) Demo Desktop & tablet Mobile Material HSL RVB Custom

Erick Ghaumez 107 Jan 5, 2023
First Open Source Flutter based material design music player with audio plugin to play online music

Flutter Music App First Open Source Flutter based dribbblel Design Music Player. logo free design http://www.freeuid.com/category/free material icons

佩奇的弟弟乔治 380 Jan 4, 2023
A Flutter Material Button that animates between Progress and Error states

progress_button A Material Flutter Button that supports progress and error visuals Getting Started ProgressButton is designed to be easy to use and cu

Halil Ozercan 132 Sep 21, 2022
The Material Design Icons Icon pack available as set of Flutter Icons.

material_design_icons_flutter The Material Design Icons Icon pack available as set of Flutter Icons. Based on Material Design Icons 6.5.95. See a web

ziofat 147 Oct 26, 2022