SurveyNative
基于声明性定义(JSON)构建的原生调查。支持多种问题类型、跳过逻辑等。
特性
- 一次显示一个问题,但允许用户向上滚动查看和更改之前的答案。
- 从JSON文件中获取输入。
- 支持许多问题类型,包括单选、多选、单行文本字段、累加文本字段、段落选择、年选择器、日期选择器和表格样式问题。
- 支持子问题。
- 支持根据之前的答案显示或隐藏问题。
调查示例
JSON输入
预期的输入是一个包含questions
数组和submit
对象的数组,详细信息说明了如何提交答案。
问题中使用的关键字
某些关键字在所有问题类型中都是标准的,而其他关键字仅在特定问题类型中存在。
-
id
(String): 必填。用于标答。也用于检查显示/隐藏条件。 -
header
(String): 可选。作为章节标题显示。 -
question
(String): 必填。显示问题的文本。 -
question_type
(String): 必填。选择的选择类型可能需要额外的关键字。 -
sub_questions
(问题数组): 可选。每个问题中预期的关键字与顶级问题相同,除了标题不是必需的(或如果提供了则显示)。通常,子问题会有一个show_if
关键字,但不是必需的。子问题的show_if
部分可能引用先前的子问题答案。 -
show_if
(条件): 可选。如果没有提供,问题将默认显示。有关更多信息,请参阅下面的显示/隐藏问题的结构。
以下关键字特定于某些问题类型。
-
options
(《字符串或其它对象数组》):仅必需于single_select
、mult_select
、table_select
类型的问题。仅table_select
不支持其它对象。其它对象是一个含title
键的 JSON 对象。当选中时,用户可以在文本框中输入文本。 -
label
(《字符串》):对于single_text_field
类型的问题是可选的。 -
label_options
(包含字符串或字符串数组的数组):对于dynamic_label_text_field
是必需的。 -
input_type
(《字符串》):对于single_text_field
、dynamic_label_text_field
、add_text_field
类型问题是可选的。可以设置为number
来改变文本框的默认键盘为数字键盘。 -
max_chars
(《字符串》):对于single_text_field
、multi_text_field
、single_text_area
类型问题是可选的。决定了用户可以输入的最大字符数。 -
validations
(字典数组):对于single_text_field
、dynamic_label_text_field
、single_text_area
类型问题是可选的。当按下 "Next" 时,检查值是否符合验证。如果不满足,将调用你的ValidationFailedDelegate
的validationFailed(message: String)
。验证由以下属性组成:操作
value
或answer_to_question_id
on_fail_message
for_label
(仅用于dynamic_label_text_field
)
支持的操作
equals
not equals
greater than
greater than or equal to
less than
less than or equal to
-
values
(《字符串数组》):对于segment_select
类型问题是必需的。这是用户选择的值。 -
fields
(《字典数组》):对于multi_text_field
类型问题是必需的。每个字典必须包含一个label
键和一个input_type
键。 -
low_tag
(《字符串》):对于segment_select
类型问题是可选的。这是最低值(第一个值)的标签。 -
high_tag
(《字符串》):对于segment_select
类型问题是可选的。这是最高值(最后一个值)的标签。 -
table_questions
(《表问题数组》):对于table_select
类型问题是必需的。每个表问题都应该有一个title
和一个id
属性。 -
min_year
(《字符串》):对于year_picker
类型问题是可选的。可以是整数或 "current_year"。有关更多信息,请参阅下面的 关于年选择器的更多内容。 -
max_year
(《字符串》):对于year_picker
类型问题是可选的。可以是整数或 "current_year"。有关更多信息,请参阅下面的 关于年选择器的更多内容。 -
num_years
(《字符串》):对于year_picker
类型问题是可选的。有关更多信息,请参阅下面的 关于年选择器的更多内容。 -
initial_year
(《字符串》):对于year_picker
类型问题是可选的。如果设置,当选择器首次打开时将选择该年。 -
sort_order
(《字符串》):对于year_picker
类型问题是可选的。可能是 "ASC"(升序)或 "DESC"(降序)。默认为 "ASC"。 -
date
(《格式为 YYYY-MM-dd 的日期字符串或 "current_date"》):对于date_picker
类型问题是可选的。如果指定,选择器将最初设置为此值(除非问题已经回答,在这种情况下将设置为上一个答案)。如果没有设置,则默认为当前日期。 -
max_date
(《格式为 YYYY-MM-dd 的日期字符串或 "current_date"》):对于date_picker
类型问题是可选的。如果指定,选择器将不允许用户选择晚于此日期的日期。如果指定了 min_date 且 min_date > max_date,则两个值都将被忽略。 -
min_date
(《格式为 YYYY-MM-dd 的日期字符串或 "current_date"》):对于date_picker
类型问题是可选的。如果指定,选择器将不允许用户选择早于此日期的日期。如果指定了 min_date 且 min_date > max_date,则两个值都将被忽略。 -
date_diff
(字符串到整数的字典): 对date_picker
问题类型的可选参数。有效的键有day
、month
和year
。只有在min_date
和max_date
中恰好有一个被设置时才有效。未设置的min/max值将通过对该参数的影响来设置。如果min_date
被设置,则date_diff
应为正数;如果max_date
被设置,则为负数。如果date_diff
被设置为使得min_date
>max_date
,则两个值都将被忽略。
关于年份选择器的更多信息
您只需要指定min_year
、max_year
和num_years
中的两个。缺失的值将根据提供的信息进行计算。如果提供了三个值,则将忽略num_years
。如果提供了少于两个值,我们将为缺失的值猜测合理的值。
显示/隐藏问题的结构
一个问题是否显示或隐藏取决于show_if
键。如果键不存在,则默认显示问题。支持简单条件和决策树。决策树可以包含其他决策树,因此可以实现相当复杂的逻辑。嵌套的深度可能有限。
简单条件键
-
id
(字符串): 必需。这是问题的ID。 -
subid
(字符串): 可选。这允许访问table_select
问题的答案,或任何在字典中的答案。 -
operation
(字符串): 必需。支持的操作equals
not equals
greater than
greater than or equal to
less than
less than or equal to
包含
不包含
-
value
(任何类型): 必需。这是要比较答案的值。
决策树键
-
operation
(字符串): 必需。可以是or
或and
。如果您需要组合,则可以使用嵌套来实现。 -
subconditions
(简单条件或决策树的数组): 必需。
自定义条件
如果这些选项不够用,您可以设置一个 CustomConditionDelegate 并使用它来做出显示/隐藏的决定。
-
ids
(字符串数组):必需。必须非空。这些都是您代表需要答案来执行其显示/隐藏计算的问题的 ID。您的代表将在任何问题被回答后立即被调用,因此您可能对于某些答案没有数据。 -
operation
(字符串):必需。应该设置为 'custom'。 -
extra
(具有字符串键的字典):可选。这将传递给您的 CustomConditionDelegate 的 isConditionMet 方法。
提交
提交对象(与 questions
相似)只需两个键,即 button_title
和 url
。两者都是必需的字符串。
问题类型示例
single_select
{
"id": "ice_cream",
"header": "Question 1",
"question": "What is your favorite ice cream flavor?",
"question_type": "single_select",
"options": [
"Strawberry",
"Chocolate",
"Vanilla",
{
"title": "Other",
"type": "freeform"
}
]
}
multi_select
{
"id": "music_types",
"header": "Question 6",
"question": "What types of music do you like?",
"question_type": "multi_select",
"options": [
"Pop",
"Rock",
"Rap",
"Country",
{
"title": "Other",
"type": "freeform"
}
]
}
year_picker
{
"id": "birthyear",
"header": "Question 2",
"question": "Enter the year of your birth.",
"question_type": "year_picker"
"max_year" : "current_year",
"num_years" : "125",
"sort_order" : "DESC"
}
日期选择器
{
"id": "date",
"header": "Question 11",
"question": "What is was the best day of the last year?",
"question_type": "date_picker",
"date" : "current_date",
"max_date" : "current_date",
"date_diff" : { "year" : -1 },
}
单行文本字段
{
"id": "age",
"header": "Question 4",
"question": "What is your current age in years?",
"question_type": "single_text_field",
"label": "Years",
"input_type": "number",
"max_chars": "2",
"validations": [
{
"operation": "greater than",
"value": 10,
"on_fail_message": "Age must be at least 10"
},
{
"operation": "less than",
"value": 80,
"on_fail_message": "You must be 80 or younger"
}
]
}
单行文本区域
{
"id": "perfect_day",
"header": "Question 2",
"question": "How would you describe your perfect day?",
"question_type": "single_text_area"
}
多行文本字段
{
"id":"pets",
"header": "Question 12",
"question": "How many pets do you have?",
"question_type": "multi_text_field",
"fields": [
{
"label" : "Dogs",
"input_type" : "number"
},
{
"label" : "Cats",
"input_type" : "number"
}
]
}
动态标签文本字段
{
"id": "height",
"header": "Question 7",
"question": "How tall are you?",
"question_type": "dynamic_label_text_field",
"label_options": [
[
"Feet",
"Inches"
],
"Centimeters"
],
"options_metadata": {
"id": "unit_system",
"types": [
"imperial",
"metric"
]
},
"input_type": "number",
"validations": [
{
"for_label": "Feet",
"operation": "greater than",
"value": 3,
"on_fail_message": "Height must be at least 4 feet"
},
{
"for_label": "Feet",
"operation": "less than",
"value": 10,
"on_fail_message": "Height must be less than 10 feet"
},
{
"for_label": "Centimeters",
"operation": "greater than",
"value": 100,
"on_fail_message": "Height must be at least 100cm"
},
{
"for_label": "Centimeters",
"operation": "less than",
"value": 250,
"on_fail_message": "Height must be less than 250cm"
}
]
}
添加文本字段
{
"id": "which_sports",
"question": "Which sports do you like to play?",
"question_type": "add_text_field",
"input_type": "default"
}
分段选择
{
"id": "happiness",
"header": "Question 8",
"question": "How happy are you?",
"question_type": "segment_select",
"low_tag": "Not happy",
"high_tag": "Super happy",
"values": [
"1",
"2",
"3",
"4",
"5",
"6",
"7"
]
}
table_select
{
"id": "weekend_activities",
"header": "Question 9",
"question": "On the weekends, do you:",
"question_type": "table_select",
"options": [
"Yes",
"Sometimes",
"No"
],
"table_questions": [
{
"title": "Play sports?",
"id": "play_sports"
},
{
"title": "Read books?",
"id": "read_books"
},
{
"title": "Go dancing",
"id": "go_dancing"
},
{
"title": "Watch TV and movies?",
"id": "watch_tv"
}
]
}
Contributing
我们期待看到贡献的领域
- 错误修复
- 支持在每种问题类型上添加跳过按钮的可选布尔标志。
- 新的问题类型
- 可定制的样式
- 可定制的动画
- 在标题中动态替换问题编号
- 启用/禁用动画的选项
- Android移植
- 将Qualtrics/survey-monkey调查导出到SurveyNative
- CareKit/ResearchKit集成