Skip to content

Instantly share code, notes, and snippets.

@MarcioQuimbundo
Forked from slightfoot/number_input.dart
Created May 1, 2019 17:04
Show Gist options
  • Save MarcioQuimbundo/19d629aee1a72ceb1beb2d2c6facfa31 to your computer and use it in GitHub Desktop.
Save MarcioQuimbundo/19d629aee1a72ceb1beb2d2c6facfa31 to your computer and use it in GitHub Desktop.
Number Input Widget - For entering pins and other such things - #HumpDayQandA - 24th April 2019
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(ExampleApp());
class ExampleApp extends StatefulWidget {
@override
_ExampleAppState createState() => _ExampleAppState();
}
class _ExampleAppState extends State<ExampleApp> {
bool _loading = false;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: _loading
? CircularProgressIndicator()
: NumberInput(
onSubmit: (value) {
print('entered: $value');
setState(() => _loading = true);
Future.delayed(const Duration(seconds: 3), () {
if (mounted) {
setState(() => _loading = false);
}
});
},
),
),
),
);
}
}
class NumberInput extends StatefulWidget {
const NumberInput({
Key key,
this.initialValue,
this.onSubmit,
this.autoFocus = true,
this.maxLength = 6,
}) : assert(maxLength != null),
super(key: key);
final String initialValue;
final ValueChanged<String> onSubmit;
final bool autoFocus;
final int maxLength;
@override
_NumberInputState createState() => _NumberInputState();
}
class _NumberInputState extends State<NumberInput> implements TextInputClient {
TextEditingValue _editingValue;
FocusNode _focusNode;
TextInputConnection _connection;
bool get _hasInputConnection => _connection != null && _connection.attached;
@override
void initState() {
super.initState();
_editingValue = widget.initialValue != null
? TextEditingValue(
text: widget.initialValue,
selection: TextSelection.collapsed(offset: widget.initialValue.length),
)
: TextEditingValue.empty;
_focusNode = FocusNode();
_focusNode.addListener(_onFocusChanged);
if (widget.autoFocus) {
WidgetsBinding.instance.addPostFrameCallback(
(_) => requestKeyboard(),
);
}
}
void _onFocusChanged() {
if (_focusNode.hasFocus) {
_openInputConnection();
} else {
_closeInputConnectionIfNeeded();
}
setState(() {});
}
@override
void dispose() {
_focusNode?.dispose();
_closeInputConnectionIfNeeded();
super.dispose();
}
@override
Widget build(BuildContext context) {
final text = _editingValue.text;
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: requestKeyboard,
child: Row(
mainAxisSize: MainAxisSize.min,
children: List.generate(widget.maxLength, (int index) {
return Container(
margin: const EdgeInsets.only(right: 8.0),
width: 45,
height: 60,
alignment: Alignment.center,
decoration: BoxDecoration(border: Border.all(color: const Color(0xFFDEDEDE))),
child: Text(
(index < text.length) ? text[index] : '',
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 32,
),
),
);
}).toList(),
),
);
}
void requestKeyboard() {
if (_focusNode.hasFocus) {
_openInputConnection();
} else {
FocusScope.of(context).requestFocus(_focusNode);
}
}
void _openInputConnection() {
if (!_hasInputConnection) {
_connection = TextInput.attach(
this,
TextInputConfiguration(
inputType: TextInputType.number,
autocorrect: false,
inputAction: TextInputAction.done,
),
);
_connection.setEditingState(_editingValue);
}
_connection.show();
}
void _closeInputConnectionIfNeeded() {
if (_hasInputConnection) {
_connection.close();
_connection = null;
}
}
@override
void updateEditingValue(TextEditingValue value) {
setState(() {
_editingValue = value;
if (value.text.length == widget.maxLength) {
widget.onSubmit?.call(value.text);
}
});
}
@override
void updateFloatingCursor(RawFloatingCursorPoint point) {
// No cursor
}
@override
void performAction(TextInputAction action) {
_focusNode.unfocus();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment