Flutter自定义键盘布局插件super_keyboard_layout的使用
Flutter自定义键盘布局插件super_keyboard_layout的使用
特性
- 支持macOS、Windows和Linux平台。
- 允许根据当前键盘布局在物理键、逻辑键和平台特定键代码之间进行映射。
- 提供键盘布局更改的通知。
开始使用
super_keyboard_layout
插件内部使用了Rust来实现低级别的平台特定功能。如果你没有安装Rust,插件会自动下载预编译的二进制文件。如果你想从源代码编译Rust代码,可以通过rustup安装Rust。
安装Rust
对于macOS或Linux,执行以下命令:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
对于Windows,可以使用Rust Installer。
如果你已经安装了Rust,请确保更新到最新版本:
rustup update
第一次构建可能需要一些时间,因为需要安装所需的Rust目标和其他依赖项。
使用方法
import 'package:super_keyboard_layout/super_keyboard_layout.dart';
void main() async {
final manager = await KeyboardLayoutManager.instance();
if (manager.supported) {
// 运行在支持的平台上
manager.onLayoutChanged.addListener(() {
// 键盘布局已更改
print('Keyboard layout changed');
});
}
final layout = manager.currentLayout;
// 获取当前布局下带有shift键的物理键1对应的逻辑键
final logicalKey = layout.getLogicalKeyForPhysicalKey(PhysicalKeyboardKey.digit1, shift: true);
// 获取逻辑键对应的物理键
final physicalKey = layout.getPhysicalKeyForLogicalKey(LogicalKeyboardKey.keyA);
// 获取逻辑键或物理键的平台特定键代码
final platformCode = layout.getPlatformKeyCode(PhysicalKeyboardKey.digit1);
}
运行示例
示例项目位于 super_keyboard_layout/example
。你可以通过以下步骤运行示例:
flutter pub global activate melos # 如果你还没有安装melos
git clone https://github.com/superlistapp/super_native_extensions.git
cd super_native_extensions
melos bootstrap
之后,可以在VSCode中打开该文件夹并运行 super_keyboard_layout
启动配置。
示例代码
下面是一个完整的示例应用,展示如何使用 super_keyboard_layout
插件:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:super_keyboard_layout/super_keyboard_layout.dart';
late KeyboardLayoutManager _keyboardLayoutManager;
void main() async {
_keyboardLayoutManager = await KeyboardLayoutManager.instance();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Super Keyboard Layout Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Super Keyboard Layout Example'),
);
}
}
class LayoutDemoWidget extends StatefulWidget {
const LayoutDemoWidget({super.key});
@override
State<LayoutDemoWidget> createState() => _LayoutDemoWidgetState();
}
class _LayoutDemoWidgetState extends State<LayoutDemoWidget> {
late FocusNode _focusNode;
PhysicalKeyboardKey? _lastKey;
@override
void initState() {
super.initState();
_focusNode = FocusNode(debugLabel: 'Example focus node');
_focusNode.onKeyEvent = _onKeyEvent;
_focusNode.requestFocus();
_keyboardLayoutManager.onLayoutChanged.addListener(_layoutChanged);
}
KeyEventResult _onKeyEvent(FocusNode node, KeyEvent event) {
if (event is KeyDownEvent) {
setState(() {
_lastKey = event.physicalKey;
});
}
return KeyEventResult.handled;
}
@override
void dispose() {
_focusNode.dispose();
_keyboardLayoutManager.onLayoutChanged.removeListener(_layoutChanged);
super.dispose();
}
void _layoutChanged() {
setState(() {});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Keyboard layout has changed."),
duration: Duration(milliseconds: 1500),
),
);
}
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
border: Border.all(
color: _focusNode.hasFocus ? Colors.red : Colors.grey, width: 2),
),
child: FocusableActionDetector(
onFocusChange: (_) {
setState(() {});
},
focusNode: _focusNode,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTapDown: (details) {
_focusNode.requestFocus();
},
child: _lastKey == null
? const Text('Press any key')
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text("Pressed physical key:",
style: TextStyle(fontWeight: FontWeight.bold)),
Text(_lastKey!.toString()),
const SizedBox(
height: 10,
),
const Text('Logical key for current keyboard layout:',
style: TextStyle(fontWeight: FontWeight.bold)),
Text(_keyboardLayoutManager.currentLayout
.getLogicalKeyForPhysicalKey(_lastKey!)
?.toString() ??
'null'),
const Text(
'Logical key for current keyboard layout (with shift):',
style: TextStyle(fontWeight: FontWeight.bold)),
Text(_keyboardLayoutManager.currentLayout
.getLogicalKeyForPhysicalKey(_lastKey!, shift: true)
?.toString() ??
'null'),
const Text(
'Logical key for current keyboard layout (with alt):',
style: TextStyle(fontWeight: FontWeight.bold)),
Text(_keyboardLayoutManager.currentLayout
.getLogicalKeyForPhysicalKey(_lastKey!, alt: true)
?.toString() ??
'null'),
const SizedBox(
height: 20,
),
const Text(
'Because this functionality is intended for '
'keyboard shortcuts, only ASCII capable keyboard '
'layouts are supported.\nOn Linux switching between '
'keyboards is only recognized after pressing a key from'
' new layout.',
style: TextStyle(fontSize: 11.5),
),
],
),
),
),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (!_keyboardLayoutManager.supported)
const Text(
'KeyboardLayoutManager is not supported on this platform.',
),
if (_keyboardLayoutManager.supported) const LayoutDemoWidget(),
],
),
),
),
);
}
}
额外信息
此插件仍处于开发的早期阶段且具有实验性质。欢迎提交PRs和bug reports!
更多关于Flutter自定义键盘布局插件super_keyboard_layout的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter自定义键盘布局插件super_keyboard_layout的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter项目中使用super_keyboard_layout
插件来自定义键盘布局的示例代码。假设你已经将super_keyboard_layout
插件添加到了你的pubspec.yaml
文件中。
首先,确保你的pubspec.yaml
文件中包含以下依赖:
dependencies:
flutter:
sdk: flutter
super_keyboard_layout: ^最新版本号 # 请替换为实际的最新版本号
然后运行flutter pub get
来安装依赖。
接下来,我们创建一个自定义键盘布局的示例。以下是一个完整的Flutter应用程序代码,它展示了如何使用super_keyboard_layout
插件。
import 'package:flutter/material.dart';
import 'package:super_keyboard_layout/super_keyboard_layout.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Custom Keyboard Layout Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final TextEditingController _controller = TextEditingController();
final FocusNode _focusNode = FocusNode();
@override
void dispose() {
_controller.dispose();
_focusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Custom Keyboard Layout Demo'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextField(
controller: _controller,
focusNode: _focusNode,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Enter text here',
),
keyboardType: TextInputType.multiline, // For multiline input to see the effect better
inputFormatters: [
FilteringTextInputFormatter.allowed(RegExp(r'[a-zA-Z0-9 ]')),
],
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {
// Show the custom keyboard
_showCustomKeyboard();
},
child: Text('Show Custom Keyboard'),
),
],
),
),
);
}
void _showCustomKeyboard() {
showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
builder: (BuildContext context) {
return Container(
height: 300,
color: Colors.white,
child: CustomKeyboardLayout(
onKeyPressed: (String key) {
_controller.value = _controller.value.copyWith(
text: _controller.text + key,
selection: TextSelection.collapsed(
offset: _controller.text.length,
),
composing: TextRange.empty,
);
// Hide the keyboard after pressing a key
Navigator.of(context).pop();
},
keyLayout: [
[
{'key': 'Q', 'color': Colors.black},
{'key': 'W', 'color': Colors.black},
{'key': 'E', 'color': Colors.black},
{'key': 'R', 'color': Colors.black},
{'key': 'T', 'color': Colors.black},
{'key': 'Y', 'color': Colors.black},
{'key': 'U', 'color': Colors.black},
{'key': 'I', 'color': Colors.black},
{'key': 'O', 'color': Colors.black},
{'key': 'P', 'color': Colors.black},
],
[
{'key': 'A', 'color': Colors.black},
{'key': 'S', 'color': Colors.black},
{'key': 'D', 'color': Colors.black},
{'key': 'F', 'color': Colors.black},
{'key': 'G', 'color': Colors.black},
{'key': 'H', 'color': Colors.black},
{'key': 'J', 'color': Colors.black},
{'key': 'K', 'color': Colors.black},
{'key': 'L', 'color': Colors.black},
],
[
{'key': 'Z', 'color': Colors.black},
{'key': 'X', 'color': Colors.black},
{'key': 'C', 'color': Colors.black},
{'key': 'V', 'color': Colors.black},
{'key': 'B', 'color': Colors.black},
{'key': 'N', 'color': Colors.black},
{'key': 'M', 'color': Colors.black},
{'key': ' ', 'color': Colors.grey}, // Space bar
],
],
),
);
},
);
}
}
// CustomKeyboardLayout widget is assumed to be provided by the super_keyboard_layout plugin
// or you may need to implement it based on the plugin's documentation.
// Here's a placeholder for what it might look like:
class CustomKeyboardLayout extends StatelessWidget {
final List<List<Map<String, dynamic>>> keyLayout;
final ValueChanged<String> onKeyPressed;
const CustomKeyboardLayout({
Key key,
@required this.keyLayout,
@required this.onKeyPressed,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 10, // Adjust based on your layout
crossAxisSpacing: 4.0,
mainAxisSpacing: 4.0,
),
itemCount: keyLayout.expand((row) => row).length,
itemBuilder: (context, index) {
final keyData = keyLayout.expanded.toList()[index];
return GestureDetector(
onTap: () => onKeyPressed(keyData['key']),
child: Container(
decoration: BoxDecoration(
color: keyData['color'] ?? Colors.grey,
borderRadius: BorderRadius.circular(8),
),
alignment: Alignment.center,
child: Text(
keyData['key'],
style: TextStyle(fontSize: 20),
),
),
);
},
);
}
}
请注意,上面的CustomKeyboardLayout
类是一个假设的实现,因为实际的super_keyboard_layout
插件可能提供了不同的API来创建自定义键盘布局。你需要参考该插件的文档来调整代码以匹配其实际的API。
此外,上面的代码示例中,当点击自定义键盘上的键时,键盘会自动隐藏。你可能需要根据实际需求调整这一行为。
务必查阅super_keyboard_layout
插件的官方文档,以确保你使用的是最新和最准确的API。