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

Flutter动态下拉菜单新增自定义选项功能实现求助

Flutter Firestore下拉菜单扩展:新增选项跳转+自定义输入

以下是实现需求的完整修改方案,包含两项功能的具体代码实现:

关键修改点说明

  1. 添加「新增值」选项并跳转:

    • 在下拉选项列表末尾添加特殊选项「新增值」,用_add_new_作为标识值
    • 选中该选项时,导航到新增页面AddOptionPage
    • 新增页面实现输入验证与Firestore数据提交,完成后自动返回主页
  2. 允许自定义输入:

    • 添加TextEditingController管理输入框内容
    • 选择现有选项时,自动将选项文本填充到输入框
    • 用户可直接在输入框输入自定义内容,不受现有选项限制

完整修改代码

// ignore_for_file: avoid_print
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'firebase_options.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const App());
}

class App extends StatefulWidget {
  const App({super.key});
  @override
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      debugShowCheckedModeBanner: false,
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  String? selectedOptionId;
  final TextEditingController _customValueController = TextEditingController();

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: const Center(
          child: Text('Dropdown Button'),
        ),
      ),
      body: Center(
        child: Column(mainAxisAlignment: MainAxisAlignment.start, children: [
          StreamBuilder<QuerySnapshot>(
            stream: FirebaseFirestore.instance
                .collection('options')
                .orderBy("option")
                .snapshots(),
            builder: (context, snapshot) {
              if (snapshot.hasError) {
                return Center(
                    child: Text("发生错误 ${snapshot.error}"));
              }
              List<DropdownMenuItem> optionItems = [];
              if (!snapshot.hasData) {
                return const CircularProgressIndicator();
              } else {
                final selectOption = snapshot.data?.docs.reversed.toList();
                if (selectOption != null) {
                  for (var option in selectOption) {
                    optionItems.add(
                      DropdownMenuItem(
                        value: option.id,
                        child: Text(
                          option['option'],
                        ),
                      ),
                    );
                  }
                }
                // 添加「新增值」选项
                optionItems.add(
                  const DropdownMenuItem(
                    value: '_add_new_',
                    child: Text('新增值'),
                  ),
                );
                return Padding(
                  padding: const EdgeInsets.all(10.0),
                  child: Container(
                    padding: const EdgeInsets.only(right: 15, left: 15),
                    decoration: BoxDecoration(
                      border: Border.all(color: Colors.grey, width: 2),
                      borderRadius: BorderRadius.circular(15),
                    ),
                    child: DropdownButton(
                        underline: const SizedBox(),
                        isExpanded: true,
                        hint: const Text(
                          "选择选项或新增",
                          style: TextStyle(
                              fontWeight: FontWeight.bold, fontSize: 20),
                        ),
                        value: selectedOptionId,
                        items: optionItems,
                        onChanged: (value) {
                          if (value == '_add_new_') {
                            // 跳转到新增页面
                            Navigator.push(
                              context,
                              MaterialPageRoute(builder: (context) => const AddOptionPage()),
                            );
                          } else {
                            setState(() {
                              selectedOptionId = value as String?;
                              // 将选中的选项文本填充到输入框
                              final selectedDoc = selectOption?.firstWhere((doc) => doc.id == value);
                              _customValueController.text = selectedDoc?['option'] ?? '';
                            });
                          }
                        }),
                  ),
                );
              }
            },
          ),
          // 自定义输入框
          Padding(
            padding: const EdgeInsets.all(10.0),
            child: TextField(
              controller: _customValueController,
              decoration: const InputDecoration(
                labelText: '自定义选项',
                border: OutlineInputBorder(),
                hintText: '输入内容或从下拉选择',
              ),
            ),
          ),
          // 可选:添加提交按钮,用于处理自定义输入的保存(如果需要)
          ElevatedButton(
            onPressed: () {
              final inputValue = _customValueController.text.trim();
              if (inputValue.isNotEmpty) {
                // 这里可以根据需求处理自定义输入,比如保存到Firestore或其他逻辑
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(content: Text('当前值: $inputValue')),
                );
              }
            },
            child: const Text('确认当前值'),
          )
        ]),
      ),
    );
  }
}

// 新增选项页面
class AddOptionPage extends StatefulWidget {
  const AddOptionPage({super.key});

  @override
  State<AddOptionPage> createState() => _AddOptionPageState();
}

class _AddOptionPageState extends State<AddOptionPage> {
  final TextEditingController _optionController = TextEditingController();
  final _formKey = GlobalKey<FormState>();

  Future<void> _saveOption() async {
    if (_formKey.currentState!.validate()) {
      try {
        await FirebaseFirestore.instance.collection('options').add({
          'option': _optionController.text.trim(),
        });
        if (!mounted) return;
        Navigator.pop(context);
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('选项新增成功')),
        );
      } catch (e) {
        if (!mounted) return;
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('保存失败: $e')),
        );
      }
    }
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('新增选项'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: _formKey,
          child: Column(
            children: [
              TextFormField(
                controller: _optionController,
                decoration: const InputDecoration(
                  labelText: '输入新选项',
                  border: OutlineInputBorder(),
                ),
                validator: (value) {
                  if (value == null || value.trim().isEmpty) {
                    return '请输入选项内容';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 20),
              ElevatedButton(
                onPressed: _saveOption,
                child: const Text('保存'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

功能说明

  • 下拉菜单包含Firestore中的所有现有选项,末尾添加「新增值」选项
  • 点击「新增值」会打开新增页面,输入内容并保存后自动返回主页,下拉菜单会实时更新新选项
  • 用户可以通过下方的输入框直接输入自定义内容,也可以选择现有选项自动填充输入框
  • 可选的确认按钮可以用于处理用户的最终输入值(如保存到数据库或其他业务逻辑)

内容的提问来源于stack exchange,提问作者I Can Done

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 13:05:25