native_virtual_keyboard 0.2.6
native_virtual_keyboard: ^0.2.6 copied to clipboard
An almost pixel perfect Flutter replica of iOS and Android native keyboards.
import 'package:flutter/material.dart';
import 'package:native_virtual_keyboard/native_virtual_keyboard.dart';
void main() {
runApp(const MyApp());
}
enum AnimationType {
none('No Animation'),
simultaneous('Simultaneous'),
staggeredSequential('Staggered (Sequential)'),
staggeredDiagonal('Staggered (Diagonal)');
final String label;
const AnimationType(this.label);
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
KeyboardPlatform? _selectedPlatform;
bool _useCustomTheme = false;
bool _showEnter = true;
bool _showBackspace = true;
AnimationType _animationType = AnimationType.simultaneous;
final _textController = TextEditingController();
late final VirtualKeyboardController _keyboardController;
static const _demoEnabledKeys = {
VirtualKeyboardKey.q,
VirtualKeyboardKey.w,
VirtualKeyboardKey.e,
VirtualKeyboardKey.r,
VirtualKeyboardKey.t,
VirtualKeyboardKey.y,
};
@override
void initState() {
super.initState();
_keyboardController = VirtualKeyboardController(
layout: EnglishQwertyKeyboardLayout(),
onKeyPress: _onKeyPress,
);
}
void _onKeyPress(VirtualKeyboardKey key) {
final text = _textController.text;
if (key == VirtualKeyboardKey.backspace) {
if (text.isNotEmpty) {
_textController.text = text.substring(0, text.length - 1);
}
return;
}
if (key == VirtualKeyboardKey.enter) {
_textController.text = '$text\n';
return;
}
_textController.text = text + key.text;
}
void _toggleKeys() {
final currentlyRestricted = _keyboardController.enabledKeys.value != null;
_keyboardController.setEnabledKeys(
currentlyRestricted ? null : _demoEnabledKeys,
);
}
@override
void dispose() {
_textController.dispose();
super.dispose();
}
KeyboardAnimationConfig? get _animationConfig {
return switch (_animationType) {
AnimationType.none => null,
AnimationType.simultaneous => const KeyboardAnimationConfig(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
),
AnimationType.staggeredSequential => const KeyboardAnimationConfig(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
staggerDelay: Duration(milliseconds: 30),
staggerPattern: StaggerPattern.sequential,
),
AnimationType.staggeredDiagonal => const KeyboardAnimationConfig(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
staggerDelay: Duration(milliseconds: 80),
staggerPattern: StaggerPattern.diagonal,
),
};
}
KeyboardTheme get _customTheme {
return KeyboardTheme(
backgroundColor: const Color(0xFF0F172A),
keyTheme: const KeyboardKeyTheme(
backgroundColor: Color(0xFF1E293B),
pressedBackgroundColor: Color(0xFF334155),
foregroundColor: Colors.white,
shadows: [
BoxShadow(color: Colors.black45, offset: Offset(0, 2), blurRadius: 2),
],
overlayBackgroundColor: Color(0xFF1E293B),
overlayTextColor: Colors.white,
keyTextStyle: TextStyle(
fontSize: 22,
fontWeight: FontWeight.w500,
fontFamily: 'Roboto',
),
),
specialKeyTheme: const KeyboardSpecialKeyTheme(
backgroundColor: Color(0xFF334155),
pressedBackgroundColor: Color(0xFF475569),
foregroundColor: Colors.white,
pressedOverlayColor: Colors.white12,
pressedFillIcon: true,
shadows: [
BoxShadow(color: Colors.black45, offset: Offset(0, 2), blurRadius: 2),
],
),
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
themeMode: ThemeMode.system,
theme: ThemeData.light(useMaterial3: true),
darkTheme: ThemeData.dark(useMaterial3: true),
home: Scaffold(
appBar: AppBar(
title: const Text('Native Virtual Keyboard'),
centerTitle: true,
),
body: Column(
children: [
Expanded(
child: ListView(
padding: const EdgeInsets.all(24),
children: [
const Text(
'Configuration',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
// Platform Selector
InputDecorator(
decoration: const InputDecoration(
labelText: 'Simulated Platform',
border: OutlineInputBorder(),
contentPadding: EdgeInsets.symmetric(
horizontal: 12,
vertical: 4,
),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<KeyboardPlatform?>(
value: _selectedPlatform,
isExpanded: true,
items: [
const DropdownMenuItem(
value: null,
child: Text('Auto-detect (System Default)'),
),
...KeyboardPlatform.values.map(
(e) =>
DropdownMenuItem(value: e, child: Text(e.name)),
),
],
onChanged: (value) =>
setState(() => _selectedPlatform = value),
),
),
),
const SizedBox(height: 16),
// Animation Type Selector
InputDecorator(
decoration: const InputDecoration(
labelText: 'Animation Type',
border: OutlineInputBorder(),
contentPadding: EdgeInsets.symmetric(
horizontal: 12,
vertical: 4,
),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<AnimationType>(
value: _animationType,
isExpanded: true,
items: AnimationType.values
.map(
(e) => DropdownMenuItem(
value: e,
child: Text(e.label),
),
)
.toList(),
onChanged: (value) =>
setState(() => _animationType = value!),
),
),
),
const SizedBox(height: 16),
// Toggle Keys Button — uses ValueListenableBuilder to avoid
// rebuilding the keyboard widget tree on toggle.
ValueListenableBuilder<Set<VirtualKeyboardKey>?>(
valueListenable: _keyboardController.enabledKeys,
builder: (context, enabledKeys, child) {
final isRestricted = enabledKeys != null;
return SizedBox(
height: 48,
child: FilledButton.icon(
onPressed: _toggleKeys,
icon: Icon(
isRestricted
? Icons.visibility
: Icons.visibility_off,
),
label: Text(
isRestricted
? 'Enable All Keys'
: 'Disable Some Keys (keep Q W E R T Y)',
),
),
);
},
),
const SizedBox(height: 16),
// Theme Toggle
SwitchListTile(
title: const Text('Use Custom Theme'),
subtitle: const Text('Demonstrates full customization API'),
value: _useCustomTheme,
onChanged: (v) => setState(() => _useCustomTheme = v),
),
SwitchListTile(
title: const Text('Show Enter Key'),
value: _showEnter,
onChanged: (v) => setState(() => _showEnter = v),
),
SwitchListTile(
title: const Text('Show Backspace Key'),
value: _showBackspace,
onChanged: (v) => setState(() => _showBackspace = v),
),
const Divider(height: 32),
// Text Input visualization
TextField(
controller: _textController,
readOnly: true,
autofocus: true,
showCursor: true,
decoration: const InputDecoration(
labelText: 'Typed Text',
hintText: 'Type using the virtual keyboard below...',
border: OutlineInputBorder(),
filled: true,
),
minLines: 3,
maxLines: 5,
style: const TextStyle(fontSize: 18),
),
],
),
),
// The Keyboard Widget
Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.1),
blurRadius: 10,
offset: const Offset(0, -2),
),
],
),
child: VirtualKeyboard(
platform: _selectedPlatform,
theme: _useCustomTheme ? _customTheme : null,
showEnter: _showEnter,
showBackspace: _showBackspace,
animationConfig: _animationConfig,
controller: _keyboardController,
),
),
],
),
),
);
}
}