Flutter自定义键盘插件perfect_keyboard的使用
Flutter自定义键盘插件perfect_keyboard的使用
Perfect Keyboard
插件为 Flutter 应用程序提供了一个可定制且交互式的键盘布局。它包括对多种语言的支持和高级按键管理功能,使开发者能够创建动态和本地化的键盘体验。
特性

- 高级键盘管理: 使用 `SuperKeyboardKey` 来管理按键属性及其关系。
- 多语言支持: 通过 JSON 文件轻松切换不同语言的键盘布局。
- 特殊键处理: 包括对空格、制表符、退格等特殊键的支持,使用 `SpecialKeys` 枚举。
入门指南
-
在你的
pubspec.yaml
文件中添加perfect_keyboard
依赖:dependencies: perfect_keyboard: ^0.0.1
-
安装包:
flutter pub get
-
导入并使用该包:
import 'package:perfect_keyboard/perfect_keyboard.dart';
支持的语言
- 土耳其语
- 哈萨克语
- 俄语
- 阿拉伯语
- 德语
示例代码
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:perfect_keyboard/perfect_keyboard.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Perfect Keyboard',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const SuperKeyboard(),
);
}
}
class SuperKeyboard extends StatefulWidget {
const SuperKeyboard({super.key});
[@override](/user/override)
State<SuperKeyboard> createState() => _SuperKeyboardState();
}
class _SuperKeyboardState extends State<SuperKeyboard> with SingleTickerProviderStateMixin {
List<String> specialKey = [];
List<Locale> supportedLocales = const [
Locale('tr'),
Locale('kk'),
Locale('ar'),
Locale('de'),
Locale('ru'),
];
int index = 0;
late AnimationController _controller;
late Animation<Color> _colorAnimation;
final List<Color> _colors = [
Colors.lime,
Colors.orange,
Colors.purple,
Colors.red,
Colors.blue,
Colors.yellow,
];
ValueNotifier<List<int>> highLightedKeyPosition = ValueNotifier([-1, -1]);
[@override](/user/override)
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 3),
vsync: this,
)..repeat(reverse: true);
_colorAnimation = ColorTweenSequence(_colors).animate(_controller);
}
[@override](/user/override)
void dispose() {
_controller.dispose();
highLightedKeyPosition.dispose();
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
final screenWidth = MediaQuery.sizeOf(context).width;
return AnnotatedRegion<SystemUiOverlayStyle>(
value: const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
systemNavigationBarColor: Colors.transparent,
systemNavigationBarIconBrightness: Brightness.light,
),
child: Scaffold(
backgroundColor: Colors.grey,
appBar: AppBar(
title: const Text("Super Keyboard"),
),
body: FutureBuilder<List<List<SuperKeyboardKey>>>(
future: getKeyboard(locale: supportedLocales[index]),
builder: (BuildContext context, AsyncSnapshot<List<List<SuperKeyboardKey>>> snapshot) {
if (snapshot.hasData) {
final data = snapshot.data!;
final maxKeys = data.fold<int>(0, (max, item) => item.length > max ? item.length : max);
final baseWidth = screenWidth / maxKeys;
List<Widget> columnChildren = data.map((entry) {
int specialKeysCount = entry.where((button) {
return button.isSpecial;
}).length;
double standardWidth = baseWidth - 1;
double gaps = entry.length * 0.5;
double extraWidth = screenWidth - (entry.length * standardWidth) - gaps;
double extraWidthPerSpecialKey = specialKeysCount > 0 ? extraWidth / specialKeysCount : 0;
List<Widget> rowChildren = entry.map<Widget>((button) {
double keyWidth = button.isSpecial
? standardWidth + extraWidthPerSpecialKey
: standardWidth;
return KeyWidget(
keyboardKey: button,
width: keyWidth,
colorAnimation: _colorAnimation,
onSpecialKeyChanged: (List<String> keys) {
setState(() {
specialKey = keys;
});
},
onIndexChanged: (int newIndex) {
setState(() {
index = newIndex;
});
},
highLightedKeyPosition: highLightedKeyPosition,
);
}).toList();
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: rowChildren,
);
}).toList();
return SizedBox(
width: screenWidth,
height: 400,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: columnChildren,
),
);
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
return const CircularProgressIndicator();
},
),
),
);
}
}
class KeyWidget extends StatefulWidget {
final SuperKeyboardKey keyboardKey;
final double width;
final Animation<Color> colorAnimation;
final Function(List<String>) onSpecialKeyChanged;
final Function(int) onIndexChanged;
final KeyWidget? nextKeyWidget;
final KeyWidget? previousKeyWidget;
final KeyWidget? topKeyWidget;
final KeyWidget? bottomKeyWidget;
final ValueNotifier<List<int>> highLightedKeyPosition;
const KeyWidget({
super.key,
required this.keyboardKey,
required this.width,
required this.colorAnimation,
required this.onSpecialKeyChanged,
required this.onIndexChanged,
this.nextKeyWidget,
this.previousKeyWidget,
this.topKeyWidget,
this.bottomKeyWidget,
required this.highLightedKeyPosition,
});
[@override](/user/override)
State<KeyWidget> createState() => _KeyWidgetState();
}
class _KeyWidgetState extends State<KeyWidget> {
List<String> specialKey = [];
int index = 0;
[@override](/user/override)
void initState() {
super.initState();
}
[@override](/user/override)
Widget build(BuildContext context) {
final keyLabel = widget.keyboardKey.value;
return GestureDetector(
onLongPressStart: (details) {
setState(() {
specialKey.add(keyLabel.toLowerCase());
});
widget.onSpecialKeyChanged(specialKey);
},
onLongPressEnd: (details) {
setState(() {
specialKey.clear();
});
widget.onSpecialKeyChanged(specialKey);
},
onHorizontalDragEnd: (DragEndDetails details) {
if (keyLabel == 'Space') {
if (details.velocity.pixelsPerSecond.dx > 500) {
setState(() {
index = (index + 1) % 5;
widget.onIndexChanged(index);
});
} else if (details.velocity.pixelsPerSecond.dx < -500) {
setState(() {
index = (index - 1 + 6) % 5;
widget.onIndexChanged(index);
});
}
}
},
child: InkWell(
onTap: () async {
if (specialKey.isNotEmpty) {
print("${specialKey.map((element) => '$element+').toString().replaceAll('(', '').replaceAll(')', '').replaceAll(' ', '').replaceAll(',', '')}$keyLabel");
} else {
print(keyLabel);
}
await animateKey();
},
customBorder: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
child: Padding(
padding: const EdgeInsets.only(left: 0.25, right: 0.25),
child: AnimatedBuilder(
animation: widget.colorAnimation,
builder: (context, child) {
return ValueListenableBuilder(
builder: (context, val, child) {
return Ink(
width: widget.width - 0.5,
height: 50,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: widget.colorAnimation.value.withAlpha(100),
blurRadius: 20.0,
spreadRadius: 10.0,
offset: const Offset(0, 5)),
],
borderRadius: BorderRadius.circular(25),
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.black.withOpacity(0.5),
Colors.black.withOpacity(0.7),
Colors.black.withOpacity(0.75),
Colors.black.withOpacity(0.7),
Colors.black.withOpacity(0.5),
],
),
border: Border.all(
color: val.first == widget.keyboardKey.rowIndex && val.last == widget.keyboardKey.columnIndex
? Colors.white
: widget.colorAnimation.value,
width: 1.5,
),
),
child: Stack(
children: [
if (widget.keyboardKey.shiftKey != null)
Positioned(
top: 5,
left: 8,
child: Text(
widget.keyboardKey.shiftKey!,
style: const TextStyle(fontSize: 9, color: Colors.white),
maxLines: 1,
),
),
Positioned.fill(
child: Align(
alignment: Alignment.center,
child: Builder(builder: (context) {
if (keyLabel == 'Space') {
return const Icon(
Icons.space_bar,
color: Colors.white,
);
} else if (keyLabel == 'Tab') {
return const Icon(
Icons.keyboard_tab,
color: Colors.white,
);
} else if (keyLabel == 'Backspace') {
return const Icon(
Icons.keyboard_backspace,
color: Colors.white,
);
} else if (keyLabel == 'Enter') {
return const Icon(
Icons.keyboard_return,
color: Colors.white,
);
} else if (keyLabel == 'Win') {
return const Icon(
Icons.window_sharp,
color: Colors.white,
);
} else if (keyLabel == 'Menu') {
return const Icon(
Icons.menu,
color: Colors.white,
);
} else {
return Text(
keyLabel,
style: const TextStyle(fontSize: 15, color: Colors.white, fontWeight: FontWeight.bold),
maxLines: 1,
);
}
}),
),
),
if (widget.keyboardKey.altGrKey != null)
Positioned(
bottom: 5,
right: 8,
child: Text(
widget.keyboardKey.altGrKey!,
style: const TextStyle(fontSize: 9, color: Colors.white),
maxLines: 1,
),
),
],
),
);
},
valueListenable: widget.highLightedKeyPosition,
);
}),
),
),
);
}
Future<void> animateKey() async {
SuperKeyboardKey currentKey = widget.keyboardKey;
while (currentKey.nextKey != null) {
currentKey = currentKey.nextKey!;
widget.highLightedKeyPosition.value = [currentKey.rowIndex, currentKey.columnIndex];
await Future.delayed(const Duration(milliseconds: 50));
}
widget.highLightedKeyPosition.value = [-1, -1];
}
}
class ColorTweenSequence extends Animatable<Color> {
final List<Color> colors;
ColorTweenSequence(this.colors);
[@override](/user/override)
Color transform(double t) {
final int index = (t * (colors.length - 1)).toInt();
final Color startColor = colors[index];
final Color endColor = colors[(index + 1) % colors.length];
final double localT = (t * (colors.length - 1)) - index;
return Color.lerp(startColor, endColor, localT) ?? startColor;
}
}
更多关于Flutter自定义键盘插件perfect_keyboard的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter自定义键盘插件perfect_keyboard的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
perfect_keyboard
是一个 Flutter 插件,用于创建自定义键盘。它允许开发者根据应用需求设计自定义的键盘布局,并集成到 Flutter 应用中。以下是如何使用 perfect_keyboard
插件的基本步骤:
1. 添加依赖
首先,在 pubspec.yaml
文件中添加 perfect_keyboard
插件的依赖:
dependencies:
flutter:
sdk: flutter
perfect_keyboard: ^1.0.0 # 请使用最新版本
然后运行 flutter pub get
来安装依赖。
2. 导入插件
在需要使用自定义键盘的 Dart 文件中导入 perfect_keyboard
插件:
import 'package:perfect_keyboard/perfect_keyboard.dart';
3. 创建自定义键盘
使用 PerfectKeyboard
组件来创建自定义键盘。你可以通过 keyboardType
属性来指定键盘的类型,或者通过 customKeys
属性来自定义键盘的布局。
PerfectKeyboard(
keyboardType: KeyboardType.numeric, // 数字键盘
onTextInput: (String text) {
// 处理键盘输入
print("Input: $text");
},
onBackspace: () {
// 处理退格键
print("Backspace pressed");
},
);
4. 自定义键盘布局
如果你想完全自定义键盘布局,可以使用 customKeys
属性。例如,创建一个包含字母和数字的键盘:
PerfectKeyboard(
customKeys: [
['1', '2', '3'],
['4', '5', '6'],
['7', '8', '9'],
['0', 'A', 'B'],
['C', 'D', 'E'],
],
onTextInput: (String text) {
print("Input: $text");
},
onBackspace: () {
print("Backspace pressed");
},
);
5. 处理键盘输入
通过 onTextInput
和 onBackspace
回调函数来处理键盘的输入和退格操作。你可以将这些输入应用到你的应用中,例如更新文本字段的内容。
class MyCustomKeyboard extends StatelessWidget {
final TextEditingController _controller = TextEditingController();
[@override](/user/override)
Widget build(BuildContext context) {
return Column(
children: [
TextField(
controller: _controller,
decoration: InputDecoration(
labelText: 'Enter text',
),
),
PerfectKeyboard(
keyboardType: KeyboardType.numeric,
onTextInput: (String text) {
_controller.text += text;
},
onBackspace: () {
if (_controller.text.isNotEmpty) {
_controller.text = _controller.text.substring(0, _controller.text.length - 1);
}
},
),
],
);
}
}