Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keyboard option in FormBuilderTouchSpin #5

Open
danielweil opened this issue Oct 31, 2020 · 5 comments
Open

Keyboard option in FormBuilderTouchSpin #5

danielweil opened this issue Oct 31, 2020 · 5 comments
Labels
enhancement New feature or request

Comments

@danielweil
Copy link

Is there a way to include a numeric keyboard when touching the field in the middle? If I still want to use the spinner but I have to type a big number.

Thanks! Love your package!

@awhitford
Copy link
Contributor

If the middle Text widget was replaced with a TextField, then the keyboard should become visible. 🤔

@danvick danvick added the enhancement New feature or request label Apr 3, 2021
@danvick
Copy link
Owner

danvick commented Apr 3, 2021

@awhitford mind taking this one?

@aaronjudd
Copy link

Maybe not a frequent request, and I guess it's pretty easy to override.. and this issue is quite old. However, having a default option to edit the entry, in addition to touch / spin would be really nice.

@myThorsten
Copy link

Would be nice to have this feature

@divan
Copy link

divan commented May 19, 2024

If the middle Text widget was replaced with a TextField then the keyboard should become visible.

And if use onChanged in TextField widget will be recreated every time the value changes, which means that the cursor and selection will be reset.

I ended up updating value only on onEditingComplete, onSubmitted and onTapOutside, but haven't properly tested it yet in all situations.

My modified version look like this:

class TouchSpin extends StatefulWidget {
  final num value;
  final num min;
  final num max;
  final num step;
  final double iconSize;
  final ValueChanged<num>? onChanged;
  final NumberFormat? displayFormat;
  final Icon subtractIcon;
  final Icon addIcon;
  final EdgeInsetsGeometry iconPadding;
  final TextStyle? textStyle;
  final Color? iconActiveColor;
  final Color? iconDisabledColor;
  final bool enabled;

  const TouchSpin({
    Key? key,
    this.value = 1.0,
    this.onChanged,
    this.min = 1.0,
    this.max = 9999999.0,
    this.step = 1.0,
    this.iconSize = 24.0,
    this.displayFormat,
    this.subtractIcon = const Icon(Icons.remove),
    this.addIcon = const Icon(Icons.add),
    this.iconPadding = const EdgeInsets.all(0),
    this.textStyle,
    this.iconActiveColor,
    this.iconDisabledColor,
    this.enabled = true,
  }) : super(key: key);

  @override
  TouchSpinState createState() => TouchSpinState();
}

class TouchSpinState extends State<TouchSpin> {
  late num _value;
  final TextEditingController _controller = TextEditingController();

  bool get minusBtnDisabled =>
      _value <= widget.min ||
      _value - widget.step < widget.min ||
      !widget.enabled;

  bool get addBtnDisabled =>
      _value >= widget.max ||
      _value + widget.step > widget.max ||
      !widget.enabled;

  @override
  void initState() {
    super.initState();
    _value = widget.value;
    _controller.text = _value.toString();
  }

  @override
  void didUpdateWidget(TouchSpin oldWidget) {
    super.didUpdateWidget(oldWidget);

    if (oldWidget.value != widget.value) {
      setState(() {
        _value = widget.value;
        _controller.text = _value.toString();
      });
      widget.onChanged?.call(widget.value);
    }
  }

  Color? _spinButtonColor(bool btnDisabled) => btnDisabled
      ? widget.iconDisabledColor ?? Theme.of(context).disabledColor
      : widget.iconActiveColor ?? Theme.of(context).textTheme.labelLarge?.color;

  void _adjustValue(num adjustment) {
    num newVal = _value + adjustment;
    setState(() {
      _value = newVal;
      _controller.text = _value.toString();
    });
    widget.onChanged?.call(newVal);
  }

  void _onTextChanged() {
    final newValue = _controller.text.isEmpty
        ? widget.min
        : num.tryParse(_controller.text) ?? widget.min;
    print(newValue);
    if (newValue != _value &&
        newValue >= widget.min &&
        newValue <= widget.max) {
      setState(() {
        _value = newValue;
      });
      widget.onChanged?.call(newValue);
    } else {
      _controller.text = _value.toString();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: <Widget>[
        IconButton(
          padding: widget.iconPadding,
          iconSize: widget.iconSize,
          color: _spinButtonColor(minusBtnDisabled),
          icon: widget.subtractIcon,
          onPressed: minusBtnDisabled ? null : () => _adjustValue(-widget.step),
        ),
        SizedBox(
          width: 50, 
          child: TextField(
            decoration: null,
            controller: _controller,
            keyboardType: TextInputType.number,
            inputFormatters: [FilteringTextInputFormatter.digitsOnly],
            textAlign: TextAlign.center,
            style: widget.textStyle,
            onEditingComplete: () => _onTextChanged(),
            onSubmitted: (_) => _onTextChanged(),
            onTapOutside: (_) => _onTextChanged(),
          ),
        ),
        IconButton(
          padding: widget.iconPadding,
          iconSize: widget.iconSize,
          color: _spinButtonColor(addBtnDisabled),
          icon: widget.addIcon,
          onPressed: addBtnDisabled ? null : () => _adjustValue(widget.step),
        ),
      ],
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

6 participants