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

Flutter中如何从TextFormField获取Icon和Color类型的值?

问题

我尝试创建一个表单用于生成新的Satisfacao对象,但需要从TextFormField中获取非字符串类型的值。期望在Color输入框输入"Colors.red"、Icon输入框输入"Icons.save"并提交表单后,_submitForm函数能创建包含对应Color和Icon参数的对象,示例如下:

Satisfacao( id: 's1', title: 'Muito Boa', color: Colors.red, icon: Icons.save, count: 0, )

我尝试了如下代码但无法正常运行:

Satisfacao类代码

import 'package:flutter/material.dart';

class Satisfacao with ChangeNotifier {
  final String id;
  final String title;
  final Color color;
  final IconData icon;
  int count;

  Satisfacao({
    required this.id,
    required this.title,
    this.color = Colors.orange,
    required this.icon,
    this.count = 0,
  });
}

表单页面代码

import 'dart:ffi';

import 'package:apetit_project/models/satisfacao.dart';
import 'package:flutter/material.dart';

class SatisfactionFormScreen extends StatefulWidget {
  const SatisfactionFormScreen({Key? key}) : super(key: key);

  @override
  State<SatisfactionFormScreen> createState() => _SatisfactionFormScreenState();
}

class _SatisfactionFormScreenState extends State<SatisfactionFormScreen> {
  final _titleFocus = FocusNode();
  final _colorFocus = FocusNode();
  final _iconFocus = FocusNode();

  final _formKey = GlobalKey<FormState>();
  final _formData = Map<String, Object>();

  @override
  void dispose() {
    super.dispose();
    _titleFocus.dispose();
  }

  void _submitForm() {
    _formKey.currentState?.save();
    final newSatisfacao = Satisfacao(
      id: _formData['id'] as String,
      title: _formData['title'] as String,
      color: _formData['color'] as Color,
      icon: _formData['icon'] as IconData,
    );

    print(newSatisfacao.id);
    print(newSatisfacao.title);
    print(newSatisfacao.color);
    print(newSatisfacao.icon);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Formulário de Satisfação'),
        actions: [
          IconButton(
            onPressed: _submitForm,
            icon: Icon(Icons.save),
          ),
        ],
      ),
      body: Padding(
        padding: const EdgeInsets.all(15),
        child: Form(
            key: _formKey,
            child: ListView(
              children: [
                TextFormField(
                  decoration: const InputDecoration(labelText: 'Id'),
                  textInputAction: TextInputAction.next,
                  onFieldSubmitted: (_) {
                    FocusScope.of(context).requestFocus(_titleFocus);
                  },
                  onSaved: (id) => _formData['id'] = id ?? '',
                ),
                TextFormField(
                  decoration: const InputDecoration(labelText: 'Title'),
                  textInputAction: TextInputAction.next,
                  focusNode: _titleFocus,
                  onFieldSubmitted: (_) {
                    FocusScope.of(context).requestFocus(_colorFocus);
                  },
                  onSaved: (title) => _formData['$title'] = title ?? '',
                ),
                TextFormField(
                  decoration: const InputDecoration(labelText: 'Color'),
                  textInputAction: TextInputAction.next,
                  focusNode: _colorFocus,
                  onFieldSubmitted: (_) {
                    FocusScope.of(context).requestFocus(_iconFocus);
                  },
                  onSaved: (color) =>
                      _formData['color'] = color ?? Colors.green,
                ),
                TextFormField(
                  decoration: const InputDecoration(labelText: 'Icon'),
                  textInputAction: TextInputAction.done,
                  focusNode: _iconFocus,
                  onFieldSubmitted: (_) => _submitForm(),
                  onSaved: (icon) => _formData['icon'] = icon ?? Icons.save,
                ),
              ],
            )),
      ),
    );
  }
}

请问如何让程序识别并获取对应的Icon和Color类型值?


解决方案

当前代码的核心问题是:TextFormField的输入是字符串类型,直接存入_formData后强转Color/IconData会触发类型转换错误;另外Title字段的onSaved逻辑有误,键名写成了$title导致无法正确取值。

解决步骤

  1. 编写字符串转类型的工具函数:将输入的"Colors.red"、"Icons.save"这类字符串映射到对应的Color和IconData实例
  2. 修正表单字段的onSaved逻辑:调用转换函数处理输入字符串,将目标类型存入_formData
  3. 修复Title字段的键名错误:把_formData['$title']改为_formData['title']

修改后的表单页面代码

import 'package:apetit_project/models/satisfacao.dart';
import 'package:flutter/material.dart';

class SatisfactionFormScreen extends StatefulWidget {
  const SatisfactionFormScreen({Key? key}) : super(key: key);

  @override
  State<SatisfactionFormScreen> createState() => _SatisfactionFormScreenState();
}

class _SatisfactionFormScreenState extends State<SatisfactionFormScreen> {
  final _titleFocus = FocusNode();
  final _colorFocus = FocusNode();
  final _iconFocus = FocusNode();

  final _formKey = GlobalKey<FormState>();
  final _formData = Map<String, Object>();

  // 字符串转Color
  Color? _stringToColor(String? colorStr) {
    if (colorStr == null || colorStr.isEmpty) return null;
    // 提取Colors后面的属性名,比如"Colors.red"提取"red"
    final colorName = colorStr.split('.').last;
    switch (colorName) {
      case 'red':
        return Colors.red;
      case 'green':
        return Colors.green;
      case 'blue':
        return Colors.blue;
      case 'orange':
        return Colors.orange;
      // 可以继续添加更多需要支持的颜色
      default:
        return Colors.orange; // 默认颜色
    }
  }

  // 字符串转IconData
  IconData? _stringToIcon(String? iconStr) {
    if (iconStr == null || iconStr.isEmpty) return null;
    // 提取Icons后面的属性名,比如"Icons.save"提取"save"
    final iconName = iconStr.split('.').last;
    switch (iconName) {
      case 'save':
        return Icons.save;
      case 'delete':
        return Icons.delete;
      case 'edit':
        return Icons.edit;
      case 'add':
        return Icons.add;
      // 可以继续添加更多需要支持的图标
      default:
        return Icons.save; // 默认图标
    }
  }

  @override
  void dispose() {
    super.dispose();
    _titleFocus.dispose();
    _colorFocus.dispose();
    _iconFocus.dispose(); // 释放未处理的FocusNode
  }

  void _submitForm() {
    if (!_formKey.currentState!.validate()) return; // 先验证表单合法性
    _formKey.currentState?.save();
    final newSatisfacao = Satisfacao(
      id: _formData['id'] as String,
      title: _formData['title'] as String,
      color: _formData['color'] as Color,
      icon: _formData['icon'] as IconData,
    );

    print(newSatisfacao.id);
    print(newSatisfacao.title);
    print(newSatisfacao.color);
    print(newSatisfacao.icon);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Formulário de Satisfação'),
        actions: [
          IconButton(
            onPressed: _submitForm,
            icon: const Icon(Icons.save),
          ),
        ],
      ),
      body: Padding(
        padding: const EdgeInsets.all(15),
        child: Form(
            key: _formKey,
            child: ListView(
              children: [
                TextFormField(
                  decoration: const InputDecoration(labelText: 'Id'),
                  textInputAction: TextInputAction.next,
                  onFieldSubmitted: (_) {
                    FocusScope.of(context).requestFocus(_titleFocus);
                  },
                  onSaved: (id) => _formData['id'] = id ?? '',
                  validator: (value) {
                    if (value == null || value.isEmpty) {
                      return '请输入Id';
                    }
                    return null;
                  },
                ),
                TextFormField(
                  decoration: const InputDecoration(labelText: 'Title'),
                  textInputAction: TextInputAction.next,
                  focusNode: _titleFocus,
                  onFieldSubmitted: (_) {
                    FocusScope.of(context).requestFocus(_colorFocus);
                  },
                  onSaved: (title) => _formData['title'] = title ?? '', // 修复键名错误
                  validator: (value) {
                    if (value == null || value.isEmpty) {
                      return '请输入Title';
                    }
                    return null;
                  },
                ),
                TextFormField(
                  decoration: const InputDecoration(labelText: 'Color'),
                  textInputAction: TextInputAction.next,
                  focusNode: _colorFocus,
                  onFieldSubmitted: (_) {
                    FocusScope.of(context).requestFocus(_iconFocus);
                  },
                  onSaved: (colorStr) {
                    final color = _stringToColor(colorStr);
                    _formData['color'] = color ?? Colors.orange;
                  },
                ),
                TextFormField(
                  decoration: const InputDecoration(labelText: 'Icon'),
                  textInputAction: TextInputAction.done,
                  focusNode: _iconFocus,
                  onFieldSubmitted: (_) => _submitForm(),
                  onSaved: (iconStr) {
                    final icon = _stringToIcon(iconStr);
                    _formData['icon'] = icon ?? Icons.save;
                  },
                ),
              ],
            )),
      ),
    );
  }
}

补充说明

  • 转换函数通过switch语句映射字符串到具体类型,可根据需求扩展更多颜色和图标的支持
  • 新增表单验证逻辑,确保必填字段不为空
  • 修复了_iconFocus未释放的问题,避免内存泄漏

内容的提问来源于stack exchange,提问作者pedro.curti

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 07:45:51