-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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