You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter如何追踪数量与类型未知的组件的用户答案?

解决方案

1. 全局存储答案状态

在页面的State类中定义一个Map,用问题的唯一ID作为键(避免列表顺序变化导致答案对应错误),存储每个问题的答案:

Map<int, dynamic> _answers = {}; // 假设FeedbackQuestion包含int类型的id字段

2. 改造题型组件,添加回调函数

每个自定义题型组件需要接收onChanged回调,将用户的选择/输入传递回父组件。以BooleanCheckboxQuestion为例:

class BooleanCheckboxQuestion extends StatelessWidget {
  final ValueChanged<bool> onChanged;
  final bool? initialValue; // 可选:支持回显初始答案

  const BooleanCheckboxQuestion({
    Key? key,
    required this.onChanged,
    this.initialValue,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Checkbox(
      value: initialValue ?? false,
      onChanged: (value) {
        if (value != null) {
          onChanged(value);
        }
      },
    );
  }
}

其他题型组件按答案类型调整泛型:

  • 单选组件:ValueChanged<String>/ValueChanged<int>(根据选项值类型)
  • 多选组件:ValueChanged<List<String>>
  • 短文本/长文本组件:ValueChanged<String>
  • 数字类型组件:ValueChanged<int>/ValueChanged<double>

3. 渲染时传递回调,实时更新答案

在ListView.builder中,给每个组件传入onChanged回调,触发状态更新:

snapshot.data![index].answer_type! == "bc" 
    ? BooleanCheckboxQuestion(
        onChanged: (value) {
          setState(() {
            _answers[snapshot.data![index].id!] = value;
          });
        },
      )
    : snapshot.data![index].answer_type! == "bs" 
        ? BooleanSelectionQuestion(
            onChanged: (value) {
              setState(() {
                _answers[snapshot.data![index].id!] = value;
              });
            },
          )
// 其余题型组件均按此逻辑添加onChanged回调

4. 实现提交逻辑,发送POST请求

定义提交方法,整理答案格式并发送请求:

Future<void> _submitFeedback() async {
  // 校验必填项(根据业务需求调整)
  for (var question in snapshot.data!) {
    if (question.isRequired && !_answers.containsKey(question.id)) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text("请完成所有必填问题")),
      );
      return;
    }
  }

  // 整理提交数据(格式需匹配API要求)
  List<Map<String, dynamic>> submitData = snapshot.data!.map((question) {
    return {
      "question_id": question.id,
      "answer": _answers[question.id] ?? "", // 未回答问题传空或默认值
    };
  }).toList();

  // 发送POST请求
  Map<String, String> requestHeaders = {
    'Content-type': 'application/json',
    'Accept': 'application/json',
    'Authorization': 'Token $apiToken'
  };

  try {
    final response = await http.post(
      Uri.parse("$submitFeedbackURL"),
      headers: requestHeaders,
      body: json.encode({"answers": submitData}),
    );

    if (response.statusCode == 200 || response.statusCode == 201) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text("提交成功")),
      );
      // 提交成功后清空答案或返回上一页
      setState(() {
        _answers.clear();
      });
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text("提交失败,请重试")),
      );
    }
  } catch (e) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text("网络异常,请检查连接")),
    );
  }
}

5. 添加提交按钮

将原ListView包裹在Column中,底部添加提交按钮:

Column(
  children: [
    Expanded(
      child: ListView.builder(
        shrinkWrap: true,
        itemCount: snapshot.data!.length,
        itemBuilder: (context, index) {
          // 已添加回调的渲染逻辑
        },
      ),
    ),
    Padding(
      padding: EdgeInsets.all(16),
      child: ElevatedButton(
        onPressed: _submitFeedback,
        child: Text("提交问卷"),
        style: ElevatedButton.styleFrom(
          minimumSize: Size(double.infinity, 50),
        ),
      ),
    ),
  ],
)

内容的提问来源于stack exchange,提问作者Gse

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 00:47:42