Flutter辅助开发插件flutter_wizard的使用
Flutter辅助开发插件flutter_wizard的使用
Flutter Wizard 是由 Jop Middelkamp 开发的一个库,它使创建自定义向导变得简单。你可以完全控制向导的外观。
使用方法
包裹你的小部件与向导控制器
要开始使用 flutter_wizard
,你需要将所有向导组件包裹在 DefaultWizardController
中,它可以接收几个参数:
- stepControllers (必需):一个
WizardStepController
列表,更多细节将在后面的章节中描述。 - initialIndex:初始显示的步骤索引。
- onStepChanged:当步骤更改时触发的回调。
- onControllerCreated:当
WizardController
创建时触发的回调。 - child (必需):
DefaultWizardController
的子小部件。这个小部件(或它的子级之一)应该包含所有需要与Wizard
小部件交互的小部件。
DefaultWizardController(
stepControllers: [
WizardStepController(
step: provider.stepOneProvider,
),
WizardStepController(
step: provider.stepTwoProvider,
isNextEnabled: false,
),
WizardStepController(
step: provider.stepThreeProvider,
),
],
child: Column(
children: [
ProgressIndicator(),
Expanded(
child: Wizard(
...
),
),
ActionBar(),
],
),
);
步骤状态管理
你可以为 DefaultWizardController
提供 stepControllers
。这些步骤控制器需要提供一个步骤状态。这个步骤状态可以是 bloc、cubit、provider、notifier 等等。唯一的要求是在你的状态管理对象中混入 WizardStep
。
当你混入 WizardStep
后,你的状态管理对象将被扩展以下属性和方法:
- wizardController:包含
WizardController
的属性。 - onControllerReceived:当
wizardController
属性被设置时触发的回调。 - onShowing:当步骤开始显示时触发的回调。
- onShowingCompleted:当步骤完成显示时触发的回调。
- onHiding:当步骤开始隐藏时触发的回调。
- onHidingCompleted:当步骤完成隐藏时触发的回调。
示例:
class StepOneProvider with WizardStep {
StepOneProvider();
final _description = BehaviorSubject<String>.seeded('');
final descriptionFocusNode = FocusNode();
final descriptionTextController = TextEditingController();
String get description {
return _description.value;
}
@override
Future<void> onShowing() async {
if (_description.value.isEmpty) {
descriptionFocusNode.requestFocus();
}
}
@override
Future<void> onHiding() async {
if (descriptionFocusNode.hasFocus) {
descriptionFocusNode.unfocus();
}
}
void updateDescription(String description) {
_description.add(description);
}
void dispose() {
descriptionTextController.dispose();
}
}
确定每个步骤显示的小部件
现在我们来设置每个步骤显示的小部件。我们需要使用 Wizard
小部件。这个小部件只接受一个参数:
- stepBuilder:用于构建步骤对应小部件的构建方法。构建方法提供了
BuildContext
和向导步骤状态。根据状态的类类型确定要显示的小部件,并将状态传递给该小部件以显示给用户。
示例:
Wizard(
stepBuilder: (context, state) {
if (state is StepOneProvider) {
return StepOne(
provider: state,
);
}
if (state is StepTwoProvider) {
return StepTwo(
provider: state,
);
}
if (state is StepThreeProvider) {
return StepThree(
provider: state,
);
}
return Container();
},
);
自定义小部件与向导的交互
你可以通过调用 WizardController.of(context)
或提供的扩展 context.wizardController
来获取 WizardController
,从而与 Wizard
小部件进行交互。
示例:移动到下一步按钮
return StreamBuilder<bool>(
stream: context.wizardController.getIsGoNextEnabledStream(),
initialData: context.wizardController.getIsGoNextEnabled(),
builder: (context, snapshot) {
if (!snapshot.hasData || snapshot.hasError) {
return const SizedBox.shrink();
}
final enabled = snapshot.data!;
return ElevatedButton(
child: const Text("Next"),
onPressed: enabled ? context.wizardController.next : null,
);
},
);
对向导事件做出反应
为了了解向导上触发的事件,你可以在小部件树中添加 WizardEventListener
。
示例:
WizardEventListener(
listener: (context, event) {
if (event is WizardForcedGoBackToEvent) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
'Step ${event.toIndex + 2} got disabled so the wizard is moving back to step ${event.toIndex + 1}.',
),
dismissDirection: DismissDirection.horizontal,
));
}
},
),
示例代码
完整的示例代码如下所示:
import 'package:flutter/material.dart';
import 'package:flutter_wizard/flutter_wizard.dart';
import 'package:provider/provider.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Wizard Example',
theme: ThemeData(
primarySwatch: Colors.blue,
colorScheme: ColorScheme(
brightness: Brightness.light,
primary: Colors.blue,
onPrimary: Colors.white,
secondary: Colors.orange,
onSecondary: Colors.white,
surface: Colors.grey.shade100,
onSurface: Colors.grey.shade700,
background: Colors.white,
onBackground: Colors.grey.shade700,
error: Colors.redAccent,
onError: Colors.white,
),
progressIndicatorTheme: ProgressIndicatorThemeData(
linearTrackColor: Colors.orange.shade100,
color: Colors.orange,
),
),
home: ProviderExamplePage.provider(),
);
}
}
class ProviderExamplePage extends StatelessWidget {
const ProviderExamplePage._({Key? key}) : super(key: key);
static Provider provider({Key? key}) {
return Provider<ProviderExamplePageProvider>(
create: (_) => ProviderExamplePageProvider(),
dispose: (_, provider) => provider.dispose(),
child: ProviderExamplePage._(
key: key,
),
);
}
@override
Widget build(BuildContext context) {
final provider = Provider.of<ProviderExamplePageProvider>(
context,
);
return DefaultWizardController(
stepControllers: [
WizardStepController(
step: provider.stepOneProvider,
),
WizardStepController(
step: provider.stepTwoProvider,
isNextEnabled: false,
),
WizardStepController(
step: provider.stepThreeProvider,
),
],
child: Builder(
builder: (context) {
return Scaffold(
appBar: AppBar(
title: StreamBuilder<int>(
stream: context.wizardController.indexStream,
initialData: context.wizardController.index,
builder: (context, snapshot) {
return Text("Wizard Example - Step ${snapshot.data! + 1}");
},
),
),
body: WizardEventListener(
listener: (context, event) {
debugPrint('### ${event.runtimeType} received');
if (event is WizardForcedGoBackToEvent) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
'Step ${event.toIndex + 2} got disabled so the wizard is moving back to step ${event.toIndex + 1}.',
),
dismissDirection: DismissDirection.horizontal,
));
}
},
child: LayoutBuilder(
builder: (context, constraints) {
return Column(
children: [
_buildProgressIndicator(
context,
),
Expanded(
child: _buildWizard(
context,
provider: provider,
constraints: constraints,
),
),
const ActionBar(),
],
);
},
),
),
);
},
),
);
}
Widget _buildWizard(
BuildContext context, {
required ProviderExamplePageProvider provider,
required BoxConstraints constraints,
}) {
final wizard = Wizard(
stepBuilder: (context, state) {
if (state is StepOneProvider) {
return StepOne(
provider: state,
);
}
if (state is StepTwoProvider) {
return StepTwo(
provider: state,
);
}
if (state is StepThreeProvider) {
return StepThree(
provider: state,
);
}
return Container();
},
);
final narrow = constraints.maxWidth <= 500;
if (narrow) {
return wizard;
}
return Row(
children: [
const SizedBox(
width: 200,
child: StepsOverview(),
),
Expanded(
child: wizard,
),
],
);
}
Widget _buildProgressIndicator(
BuildContext context,
) {
return StreamBuilder<int>(
stream: context.wizardController.indexStream,
initialData: context.wizardController.index,
builder: (context, snapshot) {
if (!snapshot.hasData || snapshot.hasError) {
return const SizedBox.shrink();
}
final index = snapshot.data!;
return StepsProgressIndicator(
count: context.wizardController.stepCount,
index: index,
);
},
);
}
}
class ProviderExamplePageProvider {
ProviderExamplePageProvider()
: stepOneProvider = StepOneProvider(),
stepTwoProvider = StepTwoProvider(),
stepThreeProvider = StepThreeProvider();
final StepOneProvider stepOneProvider;
final StepTwoProvider stepTwoProvider;
final StepThreeProvider stepThreeProvider;
Future<void> reportIssue() async {
debugPrint('Finished!');
}
Future<void> dispose() async {
stepOneProvider.dispose();
stepTwoProvider.dispose();
}
}
以上就是 flutter_wizard
插件的详细使用方法及示例代码。希望对你有所帮助!
更多关于Flutter辅助开发插件flutter_wizard的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter辅助开发插件flutter_wizard的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,flutter_wizard
是一个用于简化 Flutter 开发流程的插件,通常用于创建引导页(Wizard Pages)或分步表单。虽然具体的实现可能依赖于插件的版本和你的具体需求,但我可以提供一个基本的代码示例来展示如何使用 flutter_wizard
插件来创建一个简单的分步表单。
首先,确保你已经在 pubspec.yaml
文件中添加了 flutter_wizard
依赖:
dependencies:
flutter:
sdk: flutter
flutter_wizard: ^最新版本号 # 替换为实际的最新版本号
然后,运行 flutter pub get
来获取依赖。
接下来,是一个使用 flutter_wizard
创建分步表单的示例代码:
import 'package:flutter/material.dart';
import 'package:flutter_wizard/flutter_wizard.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Wizard Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: WizardDemo(),
);
}
}
class WizardDemo extends StatefulWidget {
@override
_WizardDemoState createState() => _WizardDemoState();
}
class _WizardDemoState extends State<WizardDemo> {
final GlobalKey<WizardControllerState> _wizardController = GlobalKey<WizardControllerState>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Wizard Demo'),
),
body: Wizard(
key: _wizardController,
steps: [
WizardStep(
title: 'Step 1',
content: TextFormField(
decoration: InputDecoration(labelText: 'Enter your name'),
),
),
WizardStep(
title: 'Step 2',
content: TextFormField(
decoration: InputDecoration(labelText: 'Enter your email'),
keyboardType: TextInputType.emailAddress,
),
),
WizardStep(
title: 'Step 3',
content: TextFormField(
decoration: InputDecoration(labelText: 'Enter your password'),
obscureText: true,
),
),
],
doneButtonTitle: 'Submit',
onDone: () async {
// 获取用户输入的数据
final WizardController controller = _wizardController.currentState!;
final Map<String, dynamic> values = await controller.collectAll();
print('Collected values: $values');
// 这里可以添加提交数据的逻辑,比如发送到服务器
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Form submitted successfully!'),
),
);
},
),
);
}
}
在这个示例中,我们创建了一个包含三个步骤的向导:
- 第一个步骤要求用户输入名字。
- 第二个步骤要求用户输入电子邮件。
- 第三个步骤要求用户输入密码。
每个步骤都使用 TextFormField
来获取用户输入。当用户完成所有步骤并点击“Submit”按钮时,onDone
回调函数将被调用,并且可以通过 controller.collectAll()
方法收集所有步骤的数据。
请注意,这个示例是基于假设的 flutter_wizard
插件的用法,实际使用时,你可能需要参考插件的官方文档来调整代码以适应最新的 API 和功能。