Flutter UI组件库插件bones_ui的使用
Flutter UI组件库插件bones_ui的使用
Bones_UI 是一个为 Dart 提供的直观且用户友好的 Web 用户界面框架。本文将介绍如何在你的 Flutter 项目中使用 Bones_UI 组件库。
CLI 工具
你可以使用 bones_ui
的命令行工具来创建或运行项目:
激活 CLI 工具
$> dart pub global activate bones_ui
查看帮助信息
$> bones_ui --help
运行单元测试
$> bones_ui test
更多详细信息可以通过以下命令查看:
$> bones_ui test --help
创建项目
$> bones_ui create -o /path/to/workspace -p project_name_dir=simple_project -p "project_name=Simple Project"
使用示例
以下是一个简单的使用示例,展示如何创建和配置一个 Bones_UI
应用:
import 'dart:html';
import 'package:bones_ui/bones_ui_kit.dart';
void main() async {
// 创建 `bones_ui` 根并初始化它:
var root = MyUIRoot(querySelector('#output'));
root.initialize();
}
// `Bones_UI` UI 根。
class MyUIRoot extends UIRoot {
MyUIRoot(Element? rootContainer) : super(rootContainer);
MyMenu _menu;
MyHome _home;
@override
void configure() {
_menu = MyMenu(content);
_home = MyHome(content);
}
// 返回菜单组件。
@override
UIComponent renderMenu() => _menu;
// 返回内容组件。
@override
UIComponent renderContent() => _home;
}
// 顶部菜单。
class MyMenu extends UIComponent {
MyMenu(Element parent) : super(parent);
// 渲染一个固定的顶部菜单,带有标题。
@override
dynamic render() {
return $div(
classes: 'menu',
style: 'position: fixed; top: 0; left: 0; width: 100%; background-color: black; color: white; padding: 10px',
content: '<span style="font-size: 120%; font-weight: bold">Bones_UI: '
'<a href="#register">Register</a> | '
'<a href="#login">Login</a>'
'</span>'
);
}
}
// 主页组件。
class MyHome extends UIComponent {
MyHome(Element parent) : super(parent);
@override
dynamic render() {
return markdownToDiv(('''
<br>
# Home
Welcome!
This is a VERY simple example!
'''));
}
}
示例代码
以下是一个更完整的示例,展示了如何使用 Bones_UI
来构建一个包含导航、页脚和可导航内容的应用:
import 'dart:html';
import 'package:bones_ui/bones_ui_kit.dart';
void main() async {
// 创建 `bones_ui` 根并初始化它:
var root = MyRoot(querySelector('#output'));
root.initialize();
}
// `Bones_UI` 根。
class MyRoot extends UIRoot {
MyRoot(super.rootContainer);
MyMenu? _menu;
MyFooter? _footer;
MyNavigable? _navigable;
@override
void configure() {
_menu = MyMenu(content);
_footer = MyFooter(content);
_navigable = MyNavigable(content);
}
// 返回菜单组件。
@override
UIComponent? renderMenu() => _menu;
// 返回页脚组件。
@override
UIComponent? renderFooter() => _footer;
// 返回内容组件。
@override
UIComponent? renderContent() => _navigable;
}
// 顶部菜单。
class MyMenu extends UIComponent {
MyMenu(super.parent);
// 渲染一个固定的顶部菜单,带有“首页”和“帮助”部分。
@override
dynamic render() {
return $div(
style:
'position: fixed; top: 0; left: 0; width: 100%; background-color: black; color: white; padding: 10px',
content: [
$span(
content:
'<span style="font-size: 120%; font-weight: bold" navigate="home">Bones_UI - </span>'),
$span(attributes: {'navigate': 'home'}, content: 'Home'),
'<span> | </span>',
$span(attributes: {'navigate': 'components'}, content: 'Components'),
'<span> | </span>',
$span(attributes: {'navigate': 'help'}, content: 'Help')
]);
}
}
// 页脚
class MyFooter extends UIComponent {
MyFooter(super.parent);
// 渲染一个固定的底部菜单。
@override
dynamic render() {
return $div(
style:
'position: absolute; position: fixed; bottom: 0; left: 0; width: 100%; background-color: rgba(0,0,0, 0.05); color: black; padding: 4px',
content: [
$span(
content:
'<span style="font-size: 90%;" navigate="home">Built with <a href="https://colossus-services.github.io/bones_ui/" target="_blank">Bones_UI</a></span>'),
]);
}
}
// 可导航的内容,根据当前路由变化。
class MyNavigable extends UINavigableComponent {
MyNavigable(Element? parent) : super(parent, ['home', 'components', 'help']);
@override
dynamic renderRoute(String? route, Map<String, String>? parameters) {
print('renderRoute> $route');
switch (route) {
case 'home':
return MyHome(content);
case 'components':
return MyComponents(content);
case 'help':
return MyHelp(content);
default:
return '?';
}
}
}
// “主页”路由。
class MyHome extends UIComponent {
MyHome(super.parent);
@override
dynamic render() {
return markdownToDiv(('''
<br>
# Home
Welcome to `Bones_UI` example
This is a VERY simple example!
See the [Help section](#help) for more
'''));
}
}
// “帮助”路由。
class MyHelp extends UIComponent {
MyHelp(super.parent);
@override
dynamic render() {
return $divInline(
style: 'width: 300px ; max-width:80vw; text-align: left',
content: [
markdownToDiv('''
<br>
# Help
See our FAQ for help:
## FAQ
- Is `Bones_UI` FREE?
YES, it is!
- Where can I get `Bones_UI`?
See the [project page](https://colossus-services.github.io/bones_ui/){:target="_blank"}.
''')
]);
}
}
// “组件”路由。
class MyComponents extends UIComponent {
MyComponents(super.parent);
@override
dynamic render() {
_buildCalendar();
return [
'<br><h1>Components</h1>',
'<hr>',
UIButton(content, 'UIButton')
..onClick.listen((event) => _showAlert('<b>UIButton Clicked:</b>',
'x: ${event.client.x}<br> y: ${event.client.y}')),
'<hr>',
UIInputTable(content, [
InputConfig('name', 'Name', type: 'text'),
InputConfig('email', 'Email',
type: 'email',
valueNormalizer: (f, v) => v?.toString().trim() ?? ''),
InputConfig('color', 'Color', type: 'color', optional: true),
InputConfig('sel', 'Select',
type: 'select', options: {'a': 'A Option', 'b': 'B Option'}),
]),
'<hr>',
_uiCalendarPopup,
'<hr>',
];
}
UICalendarPopup? _uiCalendarPopup;
void _buildCalendar() {
_uiCalendarPopup ??= UICalendarPopup(content,
backgroundBlur: 4,
mode: CalendarMode.month,
allowedModes: {CalendarMode.month, CalendarMode.day},
currentDate: DateTime(2022, 3, 20),
events: [
CalendarEvent.fromJson({
'title': 'Sleep',
'initTime': '2022/03/20 01:00',
'endTime': '2022/03/20 01:30',
}),
CalendarEvent('Meeting', DateTime(2022, 3, 20, 9, 0),
DateTime(2022, 3, 20, 9, 30),
description: 'Call'),
CalendarEvent('Lunch', DateTime(2022, 3, 20, 13, 0),
DateTime(2022, 3, 20, 14, 0),
description: 'At X'),
CalendarEvent('Dinner', DateTime(2022, 3, 20, 21, 0),
DateTime(2022, 3, 20, 21, 40),
description: 'At Y'),
CalendarEvent.byDuration(
'Wine', DateTime(2022, 3, 21, 21, 0), Duration(minutes: 40),
description: 'Wine and cheese.'),
])
..onDayClick.listen((day) {
_uiCalendarPopup!.currentDate = day;
_uiCalendarPopup!.mode = CalendarMode.day;
})
..onEventClick.listen((event) => window.alert('$event'));
}
UIDialogAlert _showAlert(String title, String text) => UIDialogAlert(
'<div style="background-color: rgba(0,0,0, 0.80); width: 100%; padding: 4px 0;">$title</div><br>$text<br>',
'OK',
style:
'width: 200px; overflow: hidden; border-radius: 8px; padding: 0px 0px 8px 0px; box-shadow: 0 6px 14px rgba(0,0,0, 0.60);')
..show();
}
Bootstrap 集成
你可以使用 bones_ui_bootstrap
包来集成 Bootstrap 和 Bones_UI。这将自动处理 JavaScript 库和 CSS 的加载,无需手动添加 HTML 或 JavaScript 代码即可实现完全集成。
单元测试
你可以在你的 Bones_UI
应用中创建单元测试。以下是一个简单的登录测试示例:
@TestOn('browser')
import 'package:bones_ui/bones_ui_test.dart';
import 'package:test/test.dart';
// 导入你的 `UIRoot` 类
import '../web/lib/ui_root.dart'; // ignore: avoid_relative_lib_imports
void main() async {
group('UIRoot', () {
late MyUIRoot uiRoot;
setUpAll(() async {
// 初始化你的 `UIRoot`:
uiRoot = await initializeTestUIRoot(MyUIRoot.new);
});
tearDownAll(() async {
await testUISleep(ms: 200);
uiRoot.clear();
});
test('menu: routes', () async {
await uiRoot.callRenderAndWait();
await testUISleep(ms: 100);
var menu = uiRoot.querySelector('.menu');
expect(menu, isNotNull);
var routes = menu!.selectAnchorLinksTargets();
expect(routes,
unorderedEquals(['register', 'login']));
});
test('login', () async {
await uiRoot.callRenderAndWait();
await testUISleep(ms: 100);
var menu = uiRoot.querySelector('.menu');
expect(menu, isNotNull);
var linkLogin = menu!
.selectAnchorElements()
.firstWhere((e) => e.href?.endsWith('#login') ?? false);
linkLogin.click();
await testUISleepUntilRoute('login', timeoutMs: 2000, minMs: 100);
expectUIRoute('login');
var navigableContent = uiRoot.querySelector('.navigable-content');
var inputElements = navigableContent!.selectInputElement();
var emailInput = inputElements.withID('email').first;
var passInput = inputElements.withID('password').first;
emailInput.value = 'admin@mail.com';
passInput.value = '123456';
await testUISleep(ms: 100);
var btnLoginDiv = uiRoot.querySelector('#btn-login');
btnLoginDiv!.click();
await testUISleepUntilRoutes(['home', ''], timeoutMs: 1000, minMs: 100);
expectUIRoutes(['home', '']);
});
});
}
要运行单元测试,请在项目目录中执行以下命令:
$> bones_ui test
要查看浏览器中运行的测试,请执行以下命令:
$> bones_ui test --show-ui
特性与问题报告
请在 issue tracker 上提交特性请求和 bug 报告。
作者与许可证
- 作者: Graciliano M. Passos (gmpassos@GitHub)
- 许可证: Artistic License - Version 2.0
通过上述内容,您可以了解如何在 Flutter 项目中使用 Bones_UI 组件库,并提供了一个完整的示例应用。希望这些信息对您有所帮助!
更多关于Flutter UI组件库插件bones_ui的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter UI组件库插件bones_ui的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用bones_ui
插件的示例代码案例。bones_ui
是一个Flutter UI组件库,提供了一系列预构建的UI组件,以便快速构建美观的用户界面。
首先,确保你的Flutter环境已经配置完毕,并且你的项目已经创建。然后,你需要在pubspec.yaml
文件中添加bones_ui
依赖:
dependencies:
flutter:
sdk: flutter
bones_ui: ^最新版本号 # 请替换为实际的最新版本号
添加完依赖后,运行flutter pub get
来安装依赖。
接下来,你可以在你的Flutter项目中使用bones_ui
提供的组件。以下是一个简单的示例,展示如何使用bones_ui
中的一些组件:
import 'package:flutter/material.dart';
import 'package:bones_ui/bones_ui.dart'; // 导入bones_ui包
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Bones UI Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Bones UI Demo'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// 使用BonesButton组件
BonesButton(
title: 'Click Me',
onPressed: () {
// 按钮点击事件处理
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Button clicked!')),
);
},
),
SizedBox(height: 20),
// 使用BonesTextField组件
BonesTextField(
labelText: 'Enter your name',
onChanged: (value) {
// 文本改变事件处理
print('Text field value: $value');
},
),
SizedBox(height: 20),
// 使用BonesCheckbox组件
BonesCheckbox(
value: true, // 初始选中状态
onChanged: (newValue) {
// 复选框改变事件处理
print('Checkbox value: $newValue');
},
label: Text('Check me'),
),
SizedBox(height: 20),
// 使用BonesRadio组件
Row(
children: <Widget>[
BonesRadio<String>(
value: 'Option 1',
groupValue: 'Option 1', // 当前选中的值
onChanged: (newValue) {
// 单选按钮改变事件处理
print('Radio selected: $newValue');
},
label: Text('Option 1'),
),
SizedBox(width: 20),
BonesRadio<String>(
value: 'Option 2',
groupValue: 'Option 1', // 当前选中的值
onChanged: (newValue) {
print('Radio selected: $newValue');
},
label: Text('Option 2'),
),
],
),
],
),
),
);
}
}
在这个示例中,我们展示了如何使用bones_ui
提供的BonesButton
、BonesTextField
、BonesCheckbox
和BonesRadio
组件。你可以根据自己的需求进一步定制这些组件的样式和行为。
请确保你已经按照bones_ui
的文档正确安装和配置了该插件,并查阅其文档以了解更多组件和用法。