Flutter Survey
受 Google 表单启发
一个简单而强大的软件包,可处理带条件问题的动态问卷/研究调查的创建。您是否曾想过实现像 Google 表单那样的表单/问卷/调查?您是否曾想过实现条件问题,根据用户的输入来显示或隐藏后续问题?此软件包可帮助您轻松构建数据收集表单。
? 特点
✔️ 消除调查的样板代码。✔️ 实现选择/多选问题。✔️ 直观地构建您自己的问题,具有无限嵌套。✔️ 使用builder方法从头开始创建自己的表单小部件进行自定义。✔️ 为您的自定义小部件添加自己的属性。✔️ 使用Form小部件支持验证。✔️ 内隐支持暗模式。
? 下一更新
✔️ 支持国际化。✔️ 支持自定义正则表达式验证。✔️ 支持各种输入格式(日期选择器、文件上传、滑块等)。✔️ 跟踪进度
⚙️ 安装
本项目需要最新版本的 Dart。您可以在 此处 下载最新版本。
1. 依赖它
将此添加到您的包的 pubspec.yaml 文件中
dependencies:
flutter_survey: '^0.1.0'
2. 安装它
您可以从命令行安装包
$ pub get
..
或者,您的编辑器可能支持 pub。请查看您编辑器的文档以了解更多信息。
3. 导入它
现在,在您的 Dart 代码中,您可以使用
import 'package:flutter_survey/survey.dart';
? 用法
首先,您必须初始化问题结构,您可以在其中指定问题类型及其可能的答案(如果有)。您还可以嵌套问题以形成条件问题。您甚至可以将其标记为必填项。这可以是 JSON 格式从服务器获取,也可以使用包中提供的 [Question] 模型构建。结构直观且决定了表单的流程。
问题类型
问题根据它们接受的输入类型进行分类。
文本输入问题
顾名思义,这里答案不限于任何特定选择。此问题的答案可以由用户键入,单行或多行。将 answerChoice 变量设置为 null 或完全省略它即可实现此功能。
Question(
question: "What is your name?",
)
单选题
这里使用单选按钮作为输入。您将可能的答案选项定义为一个 Map,其中键是答案选项。请注意,相应键的值碰巧为 null。这是因为它们没有关联的后续问题列表。
Question(
question: 'Do you like drinking coffee?',
answerChoices: {
"Yes": null,
"No": null,
},
),
多选题
这里使用复选框作为输入。与单选题类似,您将可能的答案选项定义为一个 Map,其中键是答案选项。请注意,此处相应键的值也碰巧为 null,原因与单选题相同。区别在于您将 isSingleChoice 设置为 false。
Question(
isSingleChoice: false,
question: 'What are the brands that you have tried?',
answerChoices: {
"Nestle": null,
"Starbucks": null,
"Coffee Day": null,
},
),
条件/嵌套问题
在这里,您可以定义基于前一个问题答案的后续问题。answerChoices 字段中定义的键的值决定了流程。例如,在这里,如果用户选择“是”来回答“您喜欢喝咖啡吗?”,用户将面临另一个问题“您尝试过哪些品牌?”,然后是更多嵌套。
Question(
isMandatory: true,
question: 'Do you like drinking coffee?',
answerChoices: {
"Yes": [
Question(
singleChoice: false,
question: "What are the brands that you've tried?",
answerChoices: {
"Nestle": null,
"Starbucks": null,
"Coffee Day": [
Question(
question: "Did you enjoy visiting Coffee Day?",
isMandatory: true,
answerChoices: {
"Yes": [
Question(
question: "Please tell us why you like it",
)
],
"No": [
Question(
question: "Please tell us what went wrong",
)
],
},
)
],
})
],
"No": [
Question(
question: "Do you like drinking Tea then?",
answerChoices: {
"Yes": [
Question(
question: "What are the brands that you've tried?",
answerChoices: {
"Nestle": null,
"ChaiBucks": null,
"Indian Premium Tea": [
Question(
question: "Did you enjoy visiting IPT?",
answerChoices: {
"Yes": [
Question(
question: "Please tell us why you like it",
)
],
"No": [
Question(
question: "Please tell us what went wrong",
)
],
},
)
],
})
],
"No": null,
},
)
],
},
),
表示为列表的完整问题结构
List<Question> _initialData = [
Question(
isMandatory: true,
question: 'Do you like drinking coffee?',
answerChoices: {
"Yes": [
Question(
singleChoice: false,
question: "What are the brands that you've tried?",
answerChoices: {
"Nestle": null,
"Starbucks": null,
"Coffee Day": [
Question(
question: "Did you enjoy visiting Coffee Day?",
isMandatory: true,
answerChoices: {
"Yes": [
Question(
question: "Please tell us why you like it",
)
],
"No": [
Question(
question: "Please tell us what went wrong",
)
],
},
)
],
})
],
"No": [
Question(
question: "Do you like drinking Tea then?",
answerChoices: {
"Yes": [
Question(
question: "What are the brands that you've tried?",
answerChoices: {
"Nestle": null,
"ChaiBucks": null,
"Indian Premium Tea": [
Question(
question: "Did you enjoy visiting IPT?",
answerChoices: {
"Yes": [
Question(
question: "Please tell us why you like it",
)
],
"No": [
Question(
question: "Please tell us what went wrong",
)
],
},
)
],
})
],
"No": null,
},
)
],
},
),
Question(
question: "What age group do you fall in?",
isMandatory: true,
answerChoices: const {
"18-20": null,
"20-30": null,
"Greater than 30": null,
})
];
将问题列表传递给 ConditionalQuestions Widget。
这是处理表单的主要小部件。
Survey(
initialData: _surveyData,
)
完整代码
import 'package:flutter/material.dart';
import 'package:flutter_survey/flutter_survey.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
brightness: Brightness.light,
),
darkTheme: ThemeData(
brightness: Brightness.dark,
),
themeMode: ThemeMode.system,
title: 'Flutter Demo',
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, this.title}) : super(key: key);
final String? title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title!),
),
body: Form(
key: _formKey,
child: Survey(
onNext: (questionResults) {
print(questionResults);
//store the result
},
initialData: [
Question(
isMandatory: true,
question: 'Do you like drinking coffee?',
answerChoices: {
"Yes": [
Question(
singleChoice: false,
question: "What are the brands that you've tried?",
answerChoices: {
"Nestle": null,
"Starbucks": null,
"Coffee Day": [
Question(
question: "Did you enjoy visiting Coffee Day?",
isMandatory: true,
answerChoices: {
"Yes": [
Question(
question: "Please tell us why you like it",
)
],
"No": [
Question(
question: "Please tell us what went wrong",
)
],
},
)
],
})
],
"No": [
Question(
question: "Do you like drinking Tea then?",
answerChoices: {
"Yes": [
Question(
question: "What are the brands that you've tried?",
answerChoices: {
"Nestle": null,
"ChaiBucks": null,
"Indian Premium Tea": [
Question(
question: "Did you enjoy visiting IPT?",
answerChoices: {
"Yes": [
Question(
question:
"Please tell us why you like it",
)
],
"No": [
Question(
question:
"Please tell us what went wrong",
)
],
},
)
],
})
],
"No": null,
},
)
],
},
),
Question(
question: "What age group do you fall in?",
isMandatory: true,
answerChoices: const {
"18-20": null,
"20-30": null,
"Greater than 30": null,
})
],
),
),
bottomNavigationBar: TextButton(
child: Text("Validate"),
onPressed: () {
if (_formKey.currentState!.validate()) {
//do something
}
},
),
);
}
}
? 贡献指南
通过报告错误、提交反馈和/或打开 PR 来帮助使此软件包更有用并满足社区的需求。
ℹ️ 关于我
访问我的 LinkedIn:https://www.linkedin.com/in/michel98
