Flutter核心功能扩展插件dart_board_core的使用
Flutter核心功能扩展插件dart_board_core的使用
dart_board_core
是 dart_board
的核心模块。它是 dart_board
的心脏,提供了主要的组件和导航接口。如果你将 dart_board
比喻为家庭影院系统,那么 dart_board_core
就像是你的接收器。你将各种功能(如有线电视、VCR、DVD、任天堂游戏机)插入到接收器中,而接收器再连接到电视和扬声器上。
DartBoardCore
DartBoardCore
接口让你能够访问有关系统的各种信息,例如已安装的功能、可用的输入和准备查看的通道。
通常情况下,如果你不进行AB测试或特性标志管理,你只需要使用 DartBoard
组件即可。
void main() => runApp(DartBoard(
features: [
SpaceXUIFeature(),
SpaceSceneFeature(),
ThemeFeature(data: ThemeData.dark()),
EntryPoint()
],
initialPath: '/entry_point',
));
这段代码启动了 DartBoard
,加载了你的功能,并进入初始路径 /entry_point
。对于标准用法,到这里就完成了。
AB测试与特性标志
AB切换实现
你可以通过以下方式在运行时切换不同的实现:
DartBoardCore
.instance
.setFeatureImplementation(
'YourFeatureNamespace', 'YourImplementationName')
特性标志/禁用
你可以通过以下方式禁用某个特性:
DartBoardCore
.instance
.setFeatureImplementation(
'YourFeatureNamespace', null)
这与AB切换相似,但传递 null
作为 ImplementationName
会禁用该特性。
导航
你可以通过 DartBoardCore.nav
全局访问导航功能。它维护了一个路径栈。
你可以推送新的路径,并选择是否展开它们(例如,[/a/b/c] -> [/a, /a/b, /a/b/c]
)。它提供了几种编辑栈的方法,以便根据需要修改栈。
abstract class DartBoardNav {
/// 当前活动(前台)路由
String get currentPath;
/// 监听导航更改的通知器
ChangeNotifier get changeNotifier;
/// 获取当前栈
List<DartBoardPath> get stack;
/// 将一个路由推入栈中
/// expanded 参数决定是否展开子路径(例如 /a/b/c 会推入 [/a, /a/b, /a/b/c])
void push(String path, {bool expanded});
/// 弹出最顶层的路由
void pop();
/// 弹出路由直到满足给定条件
void popUntil(bool Function(DartBoardPath path) predicate);
/// 清除所有匹配给定条件的路由
void clearWhere(bool Function(DartBoardPath path) predicate);
/// 替换栈顶路由
/// 不适用于 '/'
void replaceTop(String path);
/// 在当前路由后附加路径(例如 /a 后追加 /b 得到 /a/b)
void appendPath(String path);
/// 替换根路由(入口点)
/// 通常用于Add2App
void replaceRoot(String path);
/// 推送带有动态路由名称的路由
void pushDynamic(
{required String dynamicPathName, required WidgetBuilder builder});
}
路由类型
这些路由类型允许你匹配各种URI模式。
NamedRouteDefinition
- 匹配特定名称的部分路径,例如/page
和/details
MapRoute
- 支持多个页面的命名路由(语法糖)UriRoute
- 匹配所有到达它的路径。它可以全局处理路由,也可以与PathedRoute
结合使用以提供详细的资源解析。PathedRoute
- 用于深度链接树。例如/category/details/50
它接受一组路由定义列表。每个深度级别代表一棵树。
如何处理复杂的路由?
NamedRouteDefinition
对于静态固定目标很好用。但如果需要更高级的功能怎么办?
例如,你想让 /store/pots/2141
解析。
UriRoute
和 PathedRoute
可以解决这些问题。
PathedRoute
可以处理目录结构。你可以使用多层列表来实现。每一层可以包含任意数量的匹配器。如果路径匹配到某一层,最低级别的匹配器就会接管。
// 假代码
[
[
NamedRoute('/store', (ctx, settings) => StorePage()),
],
[
NamedRoute('/pots', (ctx, settings) => PotsPage()),
NamedRoute('/pans' (ctx, settings) => PotsPage()),
],
[
UriRoute((context, uri) => Parse and Display)
]
]
这个 PathedRoute
配置可以响应多种路由:[/store, /store/pots, /store/pans, /store/pots/*, /store/pans/*]
*
是 UriRoute
。你可以使用它来管理所有路由,或者将其与 PathedRoute
结合使用以解析信息。
UriRoute
会解析资源请求并让你访问查询参数、路径段和其他编码在页面请求中的内容。
匿名路由
有时你可能只想推送一个屏幕,而不想在特性中注册它。你可以使用以下方法:
void pushDynamic({required String dynamicRouteName, required WidgetBuilder builder});
你可以给它一个唯一的名称,例如 /YourDynamicRoute3285
。如果看到 _
,这意味着你不能共享这个路由。如果你把它给别人,他们会收到404错误。它是动态分配给用户会话的。
路由演示:SpaceX示例
SpaceX
特性被设计为演示 Add2App
和 Navigator 2.0
的用法。
[@override](/user/override)
List<RouteDefinition> get routes => [
PathedRouteDefinition([
[
NamedRouteDefinition(
route: '/launches', builder: (ctx, settings) => LaunchScreen())
],
[UriRoute((ctx, uri) => LaunchDataUriShim(uri: uri))]
]),
];
这将匹配 /launches
和 /launches/[ANY_ROUTE_NAME]
。
/launches
会将任务名称附加到URL,例如 /launches/Starlink%207
。
UriRoute
然后可以从URI中提取数据,并将其传递给页面以加载所需的数据。
有用的Widget(通用工具)
RouteWidget(嵌入式路由)
想要在任何地方使用命名路由吗?例如在一个对话框中,或者作为屏幕的一部分?
showDialog(
useSafeArea: true,
context: navigatorContext,
barrierDismissible: true,
builder: (ctx) => RouteWidget("/request_login"));
并且传递参数 RouteWidget(itemPreviewRoute, args: {"id": id})
RouteWidget
可以帮助你实现这一点,使你能够将屏幕分解成多个解耦的功能,同时共享一个核心和状态。
Convertor<In, Out>
在小部件树中进行转换
Convertor<MinesweeperState, MineFieldViewModel>(
convertor: (input) => buildVm(input),
builder: (ctx, out) => MineField(vm: out),
input: state)
只有当VM改变时才会触发更新。
这对于从数据源生成视图模型非常有用,有助于减少由于无关变化而导致的小部件重建次数。
LifecycleWidget
LifeCycleWidget(
key: ValueKey("LocatorDecoration_${T.toString()}"),
preInit: () => doSomethingBeforeCtx,
child: Builder(builder: (ctx) => child))
这个小部件可以接入生命周期的三个钩子:
/// 在 initState() 中调用,但在 super.initState() 之前
final Function() preInit;
/// 在 initState() 之后调用(带上下文)
final Function(BuildContext context) init;
/// 在 dispose() 中调用
final Function(BuildContext context) dispose;
你可以使用这个小部件来启动屏幕计时器,或者定期设置提醒/开始/停止服务等。
它在功能设置和集成方面非常有用。
示例代码
以下是一个简单的示例代码,展示了如何使用 dart_board_core
插件。
import 'package:dart_board_core/dart_board_core.dart';
import 'package:dart_board_core/interface/nav_interface.dart';
import 'package:flutter/material.dart';
/// 最小化的 Dart Board 示例。
///
/// 提供一个简单的页面和一个应用于所有页面的基本框架,
/// 并支持在两个路由之间进行基本导航。
///
/// 对于高级用法,例如应用装饰、多个功能、AB测试等,
/// 请查看项目根目录下的示例项目或访问 https://dart-board.io
void main() => runApp(DartBoard(
initialPath: '/home',
features: [ScaffoldFeature(), SimpleRouteFeature()],
));
class ScaffoldFeature extends DartBoardFeature {
[@override](/user/override)
String get namespace => 'scaffold';
[@override](/user/override)
List<DartBoardDecoration> get pageDecorations => [
DartBoardDecoration(
name: 'scaffold_widget',
decoration: (ctx, child) => Scaffold(
appBar: AppBar(title: Text('example')),
body: Container(
color: Colors.blue,
width: double.infinity,
height: double.infinity,
child: FittedBox(fit: BoxFit.contain, child: child)),
))
];
}
class SimpleRouteFeature extends DartBoardFeature {
[@override](/user/override)
String get namespace => 'main_page';
[@override](/user/override)
List<RouteDefinition> get routes => [
MapRouteDefinition(routeMap: {
'/home': (ctx, settings) => Card(
child: Column(
children: [
Text('Home Page'),
MaterialButton(
onPressed: () => DartBoardCore.nav.push("/second"),
child: Text('push another route'),
),
],
))
}),
NamedRouteDefinition(
route: '/second',
builder: (ctx, settings) => Card(
child: Column(
children: [
Text('Second Page'),
MaterialButton(
onPressed: DartBoardCore.nav.pop,
child: Text('pop'),
),
],
))),
];
}
更多关于Flutter核心功能扩展插件dart_board_core的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter核心功能扩展插件dart_board_core的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
dart_board_core
是一个用于扩展 Flutter 应用核心功能的插件。它提供了一种模块化的方式来组织和管理你的 Flutter 应用,使得代码更加结构化、可维护性更高。以下是如何使用 dart_board_core
的一些基本步骤和核心功能。
1. 安装依赖
首先,你需要在 pubspec.yaml
文件中添加 dart_board_core
依赖:
dependencies:
flutter:
sdk: flutter
dart_board_core: ^1.0.0 # 请使用最新版本
然后运行 flutter pub get
来安装依赖。
2. 基本使用
dart_board_core
的核心思想是通过 Feature
来扩展应用的功能。每个 Feature
可以包含路由、状态管理、依赖注入等。
创建一个简单的 Feature
import 'package:dart_board_core/dart_board_core.dart';
class MyFeature extends Feature {
[@override](/user/override)
List<RouteDefinition> get routes => [
RouteDefinition(
path: '/my-feature',
builder: (context) => MyFeaturePage(),
),
];
}
class MyFeaturePage extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My Feature'),
),
body: Center(
child: Text('Welcome to My Feature!'),
),
);
}
}
注册 Feature
在 main.dart
中,将 MyFeature
注册到 DartBoard
中:
import 'package:flutter/material.dart';
import 'package:dart_board_core/dart_board_core.dart';
void main() {
runApp(DartBoard(
features: [
MyFeature(),
],
home: '/my-feature',
));
}
3. 路由管理
dart_board_core
提供了一种简单的方式来管理路由。你可以通过 RouteDefinition
来定义路由,并在 Feature
中注册它们。
class MyFeature extends Feature {
[@override](/user/override)
List<RouteDefinition> get routes => [
RouteDefinition(
path: '/my-feature',
builder: (context) => MyFeaturePage(),
),
RouteDefinition(
path: '/my-feature/details',
builder: (context) => MyFeatureDetailsPage(),
),
];
}
4. 状态管理
dart_board_core
支持与不同的状态管理库(如 Provider
、Riverpod
等)集成。你可以在 Feature
中注册状态管理的提供者。
class MyFeature extends Feature {
[@override](/user/override)
List<Dependency> get dependencies => [
Dependency(
(context) => MyFeatureState(),
),
];
}
class MyFeatureState extends ChangeNotifier {
// 状态管理逻辑
}
5. 依赖注入
dart_board_core
提供了一种简单的方式来管理依赖注入。你可以通过 Dependency
来注册依赖,并在整个应用中访问它们。
class MyFeature extends Feature {
[@override](/user/override)
List<Dependency> get dependencies => [
Dependency(
(context) => MyService(),
),
];
}
class MyService {
void doSomething() {
print('Doing something!');
}
}
6. 其他功能
dart_board_core
还支持其他一些功能,如:
- Middleware:可以在路由导航前后执行一些逻辑。
- Theming:可以全局管理应用的主题。
- Localization:支持多语言管理。
7. 示例代码
以下是一个完整的示例代码:
import 'package:flutter/material.dart';
import 'package:dart_board_core/dart_board_core.dart';
void main() {
runApp(DartBoard(
features: [
MyFeature(),
],
home: '/my-feature',
));
}
class MyFeature extends Feature {
[@override](/user/override)
List<RouteDefinition> get routes => [
RouteDefinition(
path: '/my-feature',
builder: (context) => MyFeaturePage(),
),
RouteDefinition(
path: '/my-feature/details',
builder: (context) => MyFeatureDetailsPage(),
),
];
[@override](/user/override)
List<Dependency> get dependencies => [
Dependency(
(context) => MyService(),
),
];
}
class MyFeaturePage extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
final myService = context.read<MyService>();
return Scaffold(
appBar: AppBar(
title: Text('My Feature'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Welcome to My Feature!'),
ElevatedButton(
onPressed: () {
myService.doSomething();
Navigator.pushNamed(context, '/my-feature/details');
},
child: Text('Go to Details'),
),
],
),
),
);
}
}
class MyFeatureDetailsPage extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Details'),
),
body: Center(
child: Text('Details Page'),
),
);
}
}
class MyService {
void doSomething() {
print('Doing something!');
}
}