part of virtual_keyboard; /// The default keyboard height. Can we overriden by passing /// `height` argument to `VirtualKeyboard` widget. const double _virtualKeyboardDefaultHeight = 300; const int _virtualKeyboardBackspaceEventPerioud = 250; /// Virtual Keyboard widget. class VirtualKeyboard extends StatefulWidget { /// Keyboard Type: Should be inited in creation time. final VirtualKeyboardType type; /// Callback for Key press event. Called with pressed `Key` object. final Function onKeyPress; /// Virtual keyboard height. Default is 300 final double height; /// Color for key texts and icons. final Color textColor; /// Font size for keyboard keys. final double fontSize; /// The builder function will be called for each Key object. final Widget Function(BuildContext context, VirtualKeyboardKey key) builder; /// Set to true if you want only to show Caps letters. final bool alwaysCaps; VirtualKeyboard( {Key key, @required this.type, @required this.onKeyPress, this.builder, this.height = _virtualKeyboardDefaultHeight, this.textColor = Colors.black, this.fontSize = 14, this.alwaysCaps = false}) : super(key: key); @override State createState() { return _VirtualKeyboardState(); } } /// Holds the state for Virtual Keyboard class. class _VirtualKeyboardState extends State { VirtualKeyboardType type; Function onKeyPress; // The builder function will be called for each Key object. Widget Function(BuildContext context, VirtualKeyboardKey key) builder; double height; Color textColor; double fontSize; bool alwaysCaps; // Text Style for keys. TextStyle textStyle; // True if shift is enabled. bool isShiftEnabled = false; @override void didUpdateWidget(Widget oldWidget) { super.didUpdateWidget(oldWidget); setState(() { type = widget.type; onKeyPress = widget.onKeyPress; height = widget.height; textColor = widget.textColor; fontSize = widget.fontSize; alwaysCaps = widget.alwaysCaps; // Init the Text Style for keys. textStyle = TextStyle( fontSize: fontSize, color: textColor, ); }); } @override void initState() { super.initState(); type = widget.type; onKeyPress = widget.onKeyPress; height = widget.height; textColor = widget.textColor; fontSize = widget.fontSize; alwaysCaps = widget.alwaysCaps; // Init the Text Style for keys. textStyle = TextStyle( fontSize: fontSize, color: textColor, ); } @override Widget build(BuildContext context) { return type == VirtualKeyboardType.Numeric ? _numeric() : _alphanumeric(); } Widget _alphanumeric() { return Container( height: height, width: MediaQuery.of(context).size.width, child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: _rows(), ), ); } Widget _numeric() { return Container( height: height, width: MediaQuery.of(context).size.width, child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: _rows(), ), ); } /// Returns the rows for keyboard. List _rows() { // Get the keyboard Rows List> keyboardRows = type == VirtualKeyboardType.Numeric ? _getKeyboardRowsNumeric() : _getKeyboardRows(); // Generate keyboard row. List rows = List.generate(keyboardRows.length, (int rowNum) { return Material( color: Colors.transparent, child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, crossAxisAlignment: CrossAxisAlignment.center, // Generate keboard keys children: List.generate( keyboardRows[rowNum].length, (int keyNum) { // Get the VirtualKeyboardKey object. VirtualKeyboardKey virtualKeyboardKey = keyboardRows[rowNum][keyNum]; Widget keyWidget; // Check if builder is specified. // Call builder function if specified or use default // Key widgets if not. if (builder == null) { // Check the key type. switch (virtualKeyboardKey.keyType) { case VirtualKeyboardKeyType.String: // Draw String key. keyWidget = _keyboardDefaultKey(virtualKeyboardKey); break; case VirtualKeyboardKeyType.Action: // Draw action key. keyWidget = _keyboardDefaultActionKey(virtualKeyboardKey); break; } } else { // Call the builder function, so the user can specify custom UI for keys. keyWidget = builder(context, virtualKeyboardKey); if (keyWidget == null) { throw 'builder function must return Widget'; } } return keyWidget; }, ), ), ); }); return rows; } // True if long press is enabled. bool longPress; /// Creates default UI element for keyboard Key. Widget _keyboardDefaultKey(VirtualKeyboardKey key) { return Expanded( child: InkWell( onTap: () { onKeyPress(key); }, child: Container( height: height / _keyRows.length, child: Center( child: Text( alwaysCaps ? key.capsText : (isShiftEnabled ? key.capsText : key.text), style: textStyle, )), ), )); } /// Creates default UI element for keyboard Action Key. Widget _keyboardDefaultActionKey(VirtualKeyboardKey key) { // Holds the action key widget. Widget actionKey; // Switch the action type to build action Key widget. switch (key.action) { case VirtualKeyboardKeyAction.Backspace: actionKey = GestureDetector( onLongPress: () { longPress = true; // Start sending backspace key events while longPress is true Timer.periodic( Duration(milliseconds: _virtualKeyboardBackspaceEventPerioud), (timer) { if (longPress) { onKeyPress(key); } else { // Cancel timer. timer.cancel(); } }); }, onLongPressUp: () { // Cancel event loop longPress = false; }, child: Container( height: double.infinity, width: double.infinity, child: Icon( Icons.backspace, color: textColor, ), )); break; case VirtualKeyboardKeyAction.Shift: actionKey = Icon(Icons.arrow_upward, color: textColor); break; case VirtualKeyboardKeyAction.Space: actionKey = actionKey = Icon(Icons.space_bar, color: textColor); break; case VirtualKeyboardKeyAction.Return: actionKey = Icon( Icons.keyboard_return, color: textColor, ); break; } return Expanded( child: InkWell( onTap: () { if (key.action == VirtualKeyboardKeyAction.Shift) { if (!alwaysCaps) { setState(() { isShiftEnabled = !isShiftEnabled; }); } } onKeyPress(key); }, child: Container( alignment: Alignment.center, height: height / _keyRows.length, child: actionKey, ), ), ); } }