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

Flutter中如何实现点击TextField唤起ListView并填入选中内容

Flutter 实现点击 TextField 唤起列表并填充选中内容

1. 需要用到的核心 Widget 及用法

  • TextField/TextFormField:作为展示选中内容的输入框,必须设置readOnly: true,防止点击时弹出系统软键盘,同时通过onTap回调触发列表弹窗。
  • showModalBottomSheet:移动端常用的底部弹窗容器,用来承载选项列表,相比AlertDialog能提供更贴合移动端的交互体验。
  • ListView.builder:高效渲染选项列表,适合数据量不确定的场景;数据量较小时也可以用Column替代。
  • TextEditingController:绑定到每个TextField,用于更新和控制输入框的文本内容。
  • StatefulWidget:因为需要维护选中状态和更新UI,页面必须是Stateful类型,通过setState刷新输入框内容。

2. 如何将列表数据填入 TextField/TextFormField

  1. 为每个输入框创建独立的TextEditingController,示例:
    final customerController = TextEditingController();
    final brandController = TextEditingController();
    final productController = TextEditingController();
    
  2. 在列表选项的onTap回调中,将选中的内容赋值给对应控制器的text属性,通过setState触发UI更新后关闭弹窗:
    onTap: () {
      setState(() {
        controller.text = options[index];
      });
      Navigator.pop(ctx);
    }
    
  3. 将控制器绑定到对应的TextField,输入框会自动同步控制器的文本内容。

3. 点击 TextField 时如何唤起列表

  1. 给TextField设置readOnly: true,避免点击弹出软键盘;
  2. 给TextField的onTap属性绑定弹窗触发方法,示例:
    onTap: () => _showSelectionSheet(context, customers, customerController),
    
  3. 实现通用弹窗方法,调用showModalBottomSheet生成选项列表:
    void _showSelectionSheet(BuildContext context, List<String> options, TextEditingController controller) {
      showModalBottomSheet(
        context: context,
        builder: (ctx) {
          return ListView.builder(
            shrinkWrap: true,
            itemCount: options.length,
            itemBuilder: (_, index) {
              return ListTile(
                title: Text(options[index]),
                onTap: () {
                  setState(() {
                    controller.text = options[index];
                  });
                  Navigator.pop(ctx);
                },
              );
            },
          );
        },
      );
    }
    

完整示例代码

import 'package:flutter/material.dart';

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

  @override
  State<SelectionTextFieldDemo> createState() => _SelectionTextFieldDemoState();
}

class _SelectionTextFieldDemoState extends State<SelectionTextFieldDemo> {
  // 绑定每个输入框的控制器
  final customerController = TextEditingController();
  final brandController = TextEditingController();
  final productController = TextEditingController();

  // 模拟业务数据
  final List<String> customerList = ['客户A', '客户B', '客户C', '客户D'];
  final List<String> brandList = ['品牌X', '品牌Y', '品牌Z'];
  final List<String> productList = ['产品1', '产品2', '产品3', '产品4', '产品5'];

  // 通用弹窗方法:复用选择逻辑
  void _showOptionSheet(BuildContext context, List<String> options, TextEditingController controller) {
    showModalBottomSheet(
      context: context,
      isScrollControlled: true,
      builder: (ctx) {
        return Padding(
          padding: EdgeInsets.only(bottom: MediaQuery.of(ctx).viewInsets.bottom),
          child: ListView.builder(
            shrinkWrap: true,
            itemCount: options.length,
            itemBuilder: (_, index) {
              return ListTile(
                title: Text(options[index]),
                onTap: () {
                  setState(() {
                    controller.text = options[index];
                  });
                  Navigator.pop(ctx);
                },
              );
            },
          ),
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('选择器示例')),
      body: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
        child: Column(
          children: [
            TextField(
              controller: customerController,
              readOnly: true,
              decoration: const InputDecoration(
                labelText: 'Müşteri',
                border: OutlineInputBorder(),
              ),
              onTap: () => _showOptionSheet(context, customerList, customerController),
            ),
            const SizedBox(height: 16),
            TextField(
              controller: brandController,
              readOnly: true,
              decoration: const InputDecoration(
                labelText: 'Marka',
                border: OutlineInputBorder(),
              ),
              onTap: () => _showOptionSheet(context, brandList, brandController),
            ),
            const SizedBox(height: 16),
            TextField(
              controller: productController,
              readOnly: true,
              decoration: const InputDecoration(
                labelText: 'Ürün',
                border: OutlineInputBorder(),
              ),
              onTap: () => _showOptionSheet(context, productList, productController),
            ),
          ],
        ),
      ),
    );
  }

  // 销毁控制器,避免内存泄漏
  @override
  void dispose() {
    customerController.dispose();
    brandController.dispose();
    productController.dispose();
    super.dispose();
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 23:40:22