第十六回:如何使用TextField Widget

文章介绍了Flutter中的TextFieldWidget,它是用于接收用户输入文本的组件,类似于Android的EditText。文中详细讲解了其主要属性,如autofocus、keyboardType、decoration和onChanged,并提供了一个示例代码展示如何装饰和使用TextFieldWidget。


我们在上一章回中介绍了Text Widget,本章回中将介绍TextField Widget。闲话休提,让我们一起Talk Flutter吧。闲话休提,让我们一起Talk Flutter吧。

概念介绍

我们在上一章回中介绍了显示文本的Text Widget,本章回中介绍另外一个与文本相关的Widget,它叫TextField,主要用来接收用户输入的文本,它的作用与TextWidget正好相反,其实它的功能和Android中的EditText组件类似,它也是常用组件之一,本章回中将详细介绍它的使用方法。

使用方法

和其它Widget一样,TextField提供了相关的属性来控制自己,常用的属性如下:

  • autofocus 属性用来控制自动获取光标,它是布尔类型,赋值true或者false就可以;
  • keyboardType 属性用来控制键盘的输入类型,比如数字,文本等;
  • decoration 属性用来装饰文本,比如hint,文本前后的icon等,详细内容可以参考示例代码;
  • obscureText 属性用来控制是否以密码形式显示文本;
  • onChanged 属性用来获取输入的文本,这是一个方法;

示例代码

 return Scaffold(
      appBar: AppBar(
        title: Text("Example of TextField"),
      ),
      body:const TextField(
        autofocus: true,
        keyboardType: TextInputType.number,
        // onChanged: (){},
        decoration: InputDecoration(
          labelText: "Label",
          hintText: "Name",
          errorText: "It is wrong",
          prefixIcon: Icon(Icons.login),
          suffixIcon: Icon(Icons.panorama_fish_eye),
          border: OutlineInputBorder(),
        ),
        // obscureText: true,
      ),
    );

上面的代码中只列出了主要代码,完整的代码可以查看GithubEx009中的代码。在该代码中,我们给TextField装饰了Label,hint,外层的边框,并且在文本前面和后面添加了Icon,这些都是常用的内容,我们在这里就不演示程序运行结果了,建议大家自己动手去实践。

注意:使用onChanged属性时需要把TextField嵌套在一个布局类Widget中,并且布局类Widget位于StatefullWidget中。这里的代码没有演示这种嵌套关系,大家可以参考Github中Ex009中的代码。

看官们,关于"如何使用TextField Widget"的内容就介绍到这里,欢迎大家在评论区交流与讨论!

import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; class SecondPage extends StatefulWidget { const SecondPage({Key? key}) : super(key: key); @override State<SecondPage> createState() => _SecondPageState(); } class _SecondPageState extends State<SecondPage> { @override Widget build(BuildContext context) { // ️ 页面UI构建入口 return Scaffold( appBar: AppBar( title: const Text("积极日记", textDirection: TextDirection.ltr, textAlign: TextAlign.center, style: TextStyle( color: Colors.black, fontFamily: 'Comic Sans MS', fontSize: 20.0, fontWeight: FontWeight.w500, )), centerTitle: true, backgroundColor: Colors.transparent, elevation: 0, surfaceTintColor: Colors.transparent, // 避免表面色调影响 flexibleSpace: Container( decoration: const BoxDecoration( image: DecorationImage( image: AssetImage('assets/images/background.jpg'), // 图片路径 fit: BoxFit.cover, // 覆盖整个区域 ), ), ), // 返回按钮实现 leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.black), onPressed: () => Navigator.pop(context), ), ), body: Container( width: 430, height: 900, decoration: const BoxDecoration( image: DecorationImage( image: AssetImage('assets/images/background.jpg'), // 图片路径 fit: BoxFit.cover, // 覆盖整个区域 ), ), child: InputSaverContainer(), ), ); } } class InputSaverContainer extends StatefulWidget { const InputSaverContainer({super.key}); @override _InputSaverContainerState createState() => _InputSaverContainerState(); } class _InputSaverContainerState extends State<InputSaverContainer> { final TextEditingController _controller = TextEditingController(); List<String> _savedTexts = []; // 改为列表存储多个内容 Future<void> _saveInput() async { if (_controller.text.isEmpty) return; final prefs = await SharedPreferences.getInstance(); // 获取已有列表并添加新内容 //final List<String> existingList = prefs.getStringList(_storageKey) ?? []; //existingList.add(_controller.text); _savedTexts.insert(0, _controller.text); // 保存更新后的列表 //await prefs.setStringList(_storageKey, existingList); await prefs.setStringList('saved_items', _savedTexts); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("保存成功!"), duration: Duration(seconds: 1))); _controller.clear(); // 清空输入框 setState(() {}); } Future<void> _loadInputs() async { final prefs = await SharedPreferences.getInstance(); setState(() { _savedTexts = prefs.getStringList('saved_items') ?? []; }); } // 删除指定项 Future<void> _deleteItem(int index) async { final prefs = await SharedPreferences.getInstance(); setState(() { _savedTexts.removeAt(index); prefs.setStringList('saved_items', _savedTexts); }); } @override void initState() { super.initState(); _loadInputs(); } @override Widget build(BuildContext context) { return SizedBox( height: 620, width: 500, child: Container( height: 20, width: 500, padding: const EdgeInsets.all(16), decoration: const BoxDecoration( color: Colors.transparent, ), child: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: _controller, maxLines: null, // 关键参数:允许无限多行(自动扩展) minLines: 15, // 初始最小显示行数 keyboardType: TextInputType.multiline, // 启用多行键盘 textInputAction: TextInputAction.newline, // 回车键换行 decoration: const InputDecoration( labelText: null, hintText: '请记录今天做得很好的三件事和值得感恩的三件事 !', /*decoration: InputDecoration( labelText: "输入内容", prefixIcon: Icon(Icons.edit), border: OutlineInputBorder(), filled: true, fillColor: Colors.white, ),*/ ), ), const SizedBox(height: 16), SizedBox( width: double.infinity, child: ElevatedButton.icon( onPressed: _saveInput, icon: const Icon(Icons.save), label: const Text("保存内容"), style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 14), backgroundColor: Colors.black45, foregroundColor: Colors.white, elevation: 0, ), ), ), const SizedBox(height: 20), // 滑动列表区域 Container( height: 390, // 固定高度 padding: const EdgeInsets.all(12), decoration: const BoxDecoration( image: DecorationImage( image: AssetImage('assets/images/background.jpg'), // 图片路径 fit: BoxFit.cover, // 覆盖整个区域 ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Row(children: [ Icon( Icons.book, color: Colors.grey, ), Text("日记列表:", style: TextStyle(fontSize: 15)), SizedBox(height: 8) ]), Expanded( child: _savedTexts.isEmpty ? const Center(child: Text("暂无保存内容")) : ListView.builder( itemCount: _savedTexts.length, itemBuilder: (context, index) { return ListTile( /*leading: CircleAvatar( child: Text("${index + 1}"), backgroundColor: Colors.transparent, ),*/ title: Text(_savedTexts[index], textDirection: TextDirection.ltr, style: const TextStyle( color: Colors.black54, fontSize: 13.0, fontWeight: FontWeight.w400)), trailing: IconButton( // 添加删除按钮 icon: const Icon(Icons.delete, color: Colors.black), onPressed: () => _deleteItem(index), ), ); }, scrollDirection: Axis.vertical, ), ), ], ), ), ], ), ), ); } }请在这段代码中加入一段代码,实现点击Textfield先检测是否登录,如果没有登陆,弹出弹窗提醒用户登录,如果登录则可以正常使用textfield
11-24
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'dart:convert'; class ThirdPage extends StatefulWidget { const ThirdPage({Key? key}) : super(key: key); @override State<ThirdPage> createState() => _ThirdPageState(); } class _ThirdPageState extends State<ThirdPage> { @override Widget build(BuildContext context) { return MaterialApp( title: '自定义弹窗表格应用', theme: ThemeData(primarySwatch: Colors.blue), home: ProjectListPage(), ); } } class TableRowData { final String fixedContent; String editableContent; final String presetContent; TableRowData({ required this.fixedContent, this.editableContent = "", required this.presetContent, }); Map<String, dynamic> toJson() => { 'fixedContent': fixedContent, 'editableContent': editableContent, 'presetContent': presetContent, }; factory TableRowData.fromJson(Map<String, dynamic> json) => TableRowData( fixedContent: json['fixedContent'], editableContent: json['editableContent'], presetContent: json['presetContent'], ); } class Project { String name; List<TableRowData> rows; Project({required this.name, required this.rows}); Map<String, dynamic> toJson() => { 'name': name, 'rows': rows.map((row) => row.toJson()).toList(), }; factory Project.fromJson(Map<String, dynamic> json) => Project( name: json['name'], rows: (json['rows'] as List) .map((row) => TableRowData.fromJson(row)) .toList(), ); } class ProjectListPage extends StatefulWidget { @override _ProjectListPageState createState() => _ProjectListPageState(); } class _ProjectListPageState extends State<ProjectListPage> { List<Project> projects = []; @override void initState() { super.initState(); _loadProjects(); } // 加载保存的项目 Future<void> _loadProjects() async { final prefs = await SharedPreferences.getInstance(); final String? projectsJson = prefs.getString('projects'); if (projectsJson != null) { final List<dynamic> jsonList = json.decode(projectsJson); setState(() { projects = jsonList.map((json) => Project.fromJson(json)).toList(); }); } } // 保存项目列表 Future<void> _saveProjects() async { final prefs = await SharedPreferences.getInstance(); final List<Map<String, dynamic>> projectsJson = projects.map((project) => project.toJson()).toList(); await prefs.setString('projects', json.encode(projectsJson)); } // 获取第一列固定内容 String _getFixedContent(int rowIndex) { final contents = [ "固定内容行 1", "固定内容行 2", "固定内容行 3", "固定内容行 4", "固定内容行 5", "固定内容行 6", "固定内容行 7", "固定内容行 8", "固定内容行 9" ]; return contents[rowIndex]; } // 获取预设弹窗内容 String _getPresetContent(int rowIndex) { final contents = [ "安全警告:参数超出安全范围\n建议值:25-50", "操作确认:此操作不可撤", "系统通知:数据已成功保存\n位", "提醒:请完成所有必填字段\n缺失字段I", "错误:输入格式不正确\n请输入数", "性能提示:优化算法复杂度", "警告:资源使用超过阈值\n当", "确认:是否提交当前修改?\n", "成功:操作执行完成\n" ]; return contents[rowIndex]; } // 添加新项目 void _addNewProject() { List<TableRowData> rows = List.generate( 9, (index) => TableRowData( fixedContent: _getFixedContent(index), presetContent: _getPresetContent(index), )); setState(() { projects.add(Project( name: '', rows: rows, )); _saveProjects(); }); } // 删除项目 void _deleteProject(int index) { setState(() { projects.removeAt(index); _saveProjects(); }); } // 导航到表格详情页 void _navigateToTableDetail(BuildContext context, Project project) { Navigator.push( context, MaterialPageRoute( builder: (context) => TableDetailPage(project: project), ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("CBT", textDirection: TextDirection.ltr, textAlign: TextAlign.center, style: TextStyle( color: Colors.black, fontFamily: 'Comic Sans MS', fontSize: 20.0, fontWeight: FontWeight.w500, )), centerTitle: true, backgroundColor: Colors.transparent, elevation: 0, surfaceTintColor: Colors.transparent, flexibleSpace: Container( decoration: const BoxDecoration( image: DecorationImage( image: AssetImage('assets/images/background.jpg'), // 图片路径 fit: BoxFit.cover, // 覆盖整个区域 ), ), ), ), body: projects.isEmpty ? Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.table_chart, size: 64, color: Colors.grey), SizedBox(height: 16), Text('暂无表格项目', style: TextStyle(fontSize: 18)), SizedBox(height: 8), Text('点击右下角按钮创建新项目'), ], ), ) : ListView.builder( padding: EdgeInsets.all(8), itemCount: projects.length, itemBuilder: (context, index) { return Card( margin: EdgeInsets.only(bottom: 12), elevation: 0, child: ListTile( contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 20), minVerticalPadding: 24, // 设置最小垂直间距 title: TextField( controller: TextEditingController(text: projects[index].name), decoration: InputDecoration( border: InputBorder.none, contentPadding: EdgeInsets.zero, hintText: '输入项目名称', ), style: TextStyle(fontSize: 18), onChanged: (value) { setState(() { projects[index].name = value; _saveProjects(); }); }, ), trailing: Row( mainAxisSize: MainAxisSize.min, // 让Row尽量小 children: [ IconButton( icon: Icon(Icons.edit, color: Colors.blue), // 编辑图标,蓝色 onPressed: () => _navigateToTableDetail( context, projects[index]), // 编辑项目的函数,需要用户自己实现 ), IconButton( icon: Icon(Icons.delete, color: Colors.red), // 删除图标,红色 onPressed: () => _deleteProject(index), ), ], ), onTap: () => _navigateToTableDetail(context, projects[index]), ), ); }, ), floatingActionButton: FloatingActionButton( child: Icon(Icons.add), onPressed: _addNewProject, tooltip: '添加新项目', ), ); } } class TableDetailPage extends StatefulWidget { final Project project; TableDetailPage({required this.project}); @override _TableDetailPageState createState() => _TableDetailPageState(); } class _TableDetailPageState extends State<TableDetailPage> { late Project _project; bool _isSaving = false; @override void initState() { super.initState(); _project = widget.project; } Future<void> _saveProject() async { setState(() => _isSaving = true); try { final prefs = await SharedPreferences.getInstance(); final String? projectsJson = prefs.getString('projects'); List<Project> projects = []; if (projectsJson != null) { List<dynamic> jsonList = json.decode(projectsJson); projects = jsonList.map((json) => Project.fromJson(json)).toList(); } // 查找当前项目在列表中的位置 int index = projects.indexWhere((p) => p.name == _project.name); if (index != -1) { projects[index] = _project; } else { projects.add(_project); } // 保存更新后的项目列表 final String updatedJson = json.encode(projects.map((p) => p.toJson()).toList()); await prefs.setString('projects', updatedJson); ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text('保存成功!'), backgroundColor: Colors.green, duration: Duration(seconds: 2), )); } catch (e) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text('保存失败: $e'), backgroundColor: Colors.red, )); } finally { setState(() => _isSaving = false); } } /*bool _validateData() { // 实现数据验证逻辑 return true; } // 保存项目数据 Future<void> _saveProject() async { final prefs = await SharedPreferences.getInstance(); final List<Project> projects = []; // 加载现有项目 Future<void> _loadProjects() async { final String? projectsJson = prefs.getString('projects'); if (projectsJson != null) { final List<dynamic> jsonList = json.decode(projectsJson); projects .addAll(jsonList.map((json) => Project.fromJson(json)).toList()); } } // 更新当前项目 final index = projects.indexWhere((p) => p.name == _project.name); if (index != -1) { projects[index] = _project; } // 保存更新后的项目列表 Future<void> _saveProjects() async { final List<Map<String, dynamic>> projectsJson = projects.map((project) => project.toJson()).toList(); await prefs.setString('projects', json.encode(projectsJson)); } } // 编辑第二列内容 void _editSecondColumn(BuildContext context, int rowIndex) { String currentValue = _project.rows[rowIndex].editableContent; showDialog( context: context, builder: (context) => AlertDialog( title: Text('编辑内容'), content: TextField( autofocus: true, controller: TextEditingController(text: currentValue), onChanged: (value) => currentValue = value, ), actions: [ TextButton( child: Text('取消'), onPressed: () => Navigator.pop(context), ), TextButton( child: Text('保存'), onPressed: () { setState(() { _project.rows[rowIndex].editableContent = currentValue; _saveProject(); }); Navigator.pop(context); }, ), ], ), ); }*/ @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(_project.name), leading: IconButton( icon: Icon(Icons.arrow_back), onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => const ThirdPage()), // 目标页面 ); }, ), ), body: SingleChildScrollView( child: Container( padding: EdgeInsets.all(16), child: Table( border: TableBorder.all(color: Colors.grey[300]!), columnWidths: { 0: FixedColumnWidth(80), 1: FixedColumnWidth(240), 2: FixedColumnWidth(80), }, children: [ // 表头 TableRow( decoration: BoxDecoration(color: Colors.transparent), children: [ TableCell( child: Padding( padding: EdgeInsets.all(12), child: Text('固定列', style: TextStyle(fontWeight: FontWeight.bold)), )), TableCell( child: Padding( padding: EdgeInsets.all(12), child: Text('可编辑列', style: TextStyle(fontWeight: FontWeight.bold)), )), TableCell( child: Padding( padding: EdgeInsets.all(12), child: Text('操作', style: TextStyle(fontWeight: FontWeight.bold)), )), ], ), // 表格内容(9行) ...List.generate(9, (rowIndex) { return TableRow( decoration: BoxDecoration( color: Colors.transparent, ), children: [ // 第一列:固定内容,不可修改 TableCell( child: Padding( padding: EdgeInsets.all(12), child: Text( _project.rows[rowIndex].fixedContent, style: TextStyle(color: Colors.grey[700]), ), ), ), // 第二列:可编辑内容,点击编辑 TableCell( child: Padding( padding: EdgeInsets.all(8), child: TextField( controller: TextEditingController.fromValue(TextEditingValue( text: _project.rows[rowIndex].editableContent, selection: TextSelection.collapsed( offset: _project.rows[rowIndex].editableContent .length, // 光标在末尾 ), )), onChanged: (value) { setState(() { _project.rows[rowIndex].editableContent = value; }); }, textDirection: TextDirection.ltr, maxLines: null, // 关键参数:允许无限多行(自动扩展) minLines: 2, // 初始最小显示行数 keyboardType: TextInputType.multiline, // 启用多行键盘 textInputAction: TextInputAction.newline, // 回车键换行 decoration: InputDecoration( contentPadding: EdgeInsets.symmetric(horizontal: 8), hintText: '输入内容', border: InputBorder.none, ), ), ), ), // 第三列:按钮,弹出预设内容 TableCell( child: Padding( padding: EdgeInsets.all(8), child: IconButton( icon: Icon(Icons.info_outline, size: 20), color: Colors.blue, onPressed: () { showDialog( context: context, builder: (context) => AlertDialog( title: Text('系统信息'), content: SingleChildScrollView( child: Text( _project.rows[rowIndex].presetContent, style: TextStyle(fontSize: 16), ), ), actions: [ TextButton( child: Text('关闭'), onPressed: () => Navigator.pop(context), ), ], ), ); }, ), ), ), ], ); }), ], ), ), ), // 添加底部保存按钮 floatingActionButton: FloatingActionButton.extended( icon: Icon(Icons.save), label: Text(_isSaving ? '保存中...' : '保存更改'), onPressed: _isSaving ? null : _saveProject, backgroundColor: _isSaving ? Colors.grey : Colors.blue, ), ); } }在列表页的appbar加一个返回键
11-10
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'dart:convert'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: '自定义弹窗表格应用', theme: ThemeData(primarySwatch: Colors.blue), home: ProjectListPage(), ); } } class Project { String name; List<TableRowData> rows; Map<int, String> dialogContents; // 存储每行的弹窗内容 Project({ required this.name, required this.rows, Map<int, String>? dialogContents, }) : dialogContents = dialogContents ?? {}; Map<String, dynamic> toJson() => { 'name': name, 'rows': rows.map((row) => row.toJson()).toList(), 'dialogContents': dialogContents.map((key, value) => MapEntry(key.toString(), value)), }; factory Project.fromJson(Map<String, dynamic> json) => Project( name: json['name'], rows: List<TableRowData>.from(json['rows'].map((x) => TableRowData.fromJson(x))), dialogContents: json['dialogContents'] != null ? (json['dialogContents'] as Map).map((key, value) => MapEntry(int.parse(key), value.toString())) : {}, ); } class TableRowData { String fixedContent; String editableContent; TableRowData({required this.fixedContent, required this.editableContent}); Map<String, dynamic> toJson() => { 'fixedContent': fixedContent, 'editableContent': editableContent, }; factory TableRowData.fromJson(Map<String, dynamic> json) => TableRowData( fixedContent: json['fixedContent'].toString(), editableContent: json['editableContent'].toString(), ); } class ProjectListPage extends StatefulWidget { @override _ProjectListPageState createState() => _ProjectListPageState(); } class _ProjectListPageState extends State<ProjectListPage> { List<Project> projects = []; @override void initState() { super.initState(); _loadProjects(); } Future<void> _loadProjects() async { SharedPreferences prefs = await SharedPreferences.getInstance(); String? projectData = prefs.getString('projects'); if (projectData != null) { List<dynamic> jsonList = json.decode(projectData); setState(() { projects = jsonList.map((json) => Project.fromJson(json)).toList(); }); } } Future<void> _saveProjects() async { SharedPreferences prefs = await SharedPreferences.getInstance(); List<Map<String, dynamic>> jsonList = projects.map((project) => project.toJson()).toList(); prefs.setString('projects', json.encode(jsonList)); } void _addNewProject() async { final result = await Navigator.push( context, MaterialPageRoute(builder: (context) => TableEditPage()), ); if (result != null && result is Project) { setState(() { projects.add(result); _saveProjects(); }); } } void _deleteProject(int index) { setState(() { projects.removeAt(index); _saveProjects(); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('项目列表')), body: projects.isEmpty ? Center(child: Text('暂无项目,点击右下角按钮创建')) : ListView.builder( itemCount: projects.length, itemBuilder: (context, index) { return Dismissible( key: Key(projects[index].name), background: Container(color: Colors.red), confirmDismiss: (direction) async { return await showDialog( context: context, builder: (context) => AlertDialog( title: Text('确认删除'), content: Text('确定要删除项目 "${projects[index].name}" 吗?'), actions: [ TextButton( child: Text('取消'), onPressed: () => Navigator.of(context).pop(false), ), TextButton( child: Text('删除', style: TextStyle(color: Colors.red)), onPressed: () => Navigator.of(context).pop(true), ), ], ), ); }, onDismissed: (direction) => _deleteProject(index), child: ListTile( title: Text(projects[index].name), subtitle: Text('包含 ${projects[index].rows.length} 行数据'), trailing: IconButton( icon: Icon(Icons.delete, color: Colors.red), onPressed: () => _deleteProject(index), ), onTap: () async { final updated = await Navigator.push( context, MaterialPageRoute( builder: (context) => TableEditPage(project: projects[index]), ), ); if (updated != null && updated is Project) { setState(() { projects[index] = updated; _saveProjects(); }); } }, ), ); }, ), floatingActionButton: FloatingActionButton( child: Icon(Icons.add), onPressed: _addNewProject, tooltip: '创建新项目', ), ); } } class TableEditPage extends StatefulWidget { final Project? project; TableEditPage({this.project}); @override _TableEditPageState createState() => _TableEditPageState(); } class _TableEditPageState extends State<TableEditPage> { late TextEditingController projectNameController; List<TableRowData> rows = []; List<TextEditingController> editableControllers = []; Map<int, TextEditingController> dialogControllers = {}; Map<int, String> dialogContents = {}; @override void initState() { super.initState(); projectNameController = TextEditingController( text: widget.project?.name ?? '新项目 ${DateTime.now().millisecondsSinceEpoch}'); if (widget.project != null) { rows = widget.project!.rows.map((row) => TableRowData( fixedContent: row.fixedContent, editableContent: row.editableContent, )).toList(); editableControllers = rows.map((row) => TextEditingController(text: row.editableContent) ).toList(); // 初始化弹窗内容 if (widget.project!.dialogContents.isNotEmpty) { dialogContents = Map.from(widget.project!.dialogContents); } } else { // 初始添加一行 rows.add(TableRowData( fixedContent: '固定内容 1', editableContent: '', )); editableControllers.add(TextEditingController()); } // 为每行创建弹窗控制器 for (int i = 0; i < rows.length; i++) { dialogControllers[i] = TextEditingController( text: dialogContents[i] ?? '这是第${i+1}行的自定义弹窗内容\n创建时间: ${DateTime.now().toString()}' ); } } void _addNewRow() { setState(() { final newIndex = rows.length; final newRow = TableRowData( fixedContent: '固定内容 ${newIndex + 1}', editableContent: '', ); rows.add(newRow); editableControllers.add(TextEditingController()); // 为新行添加弹窗控制器 dialogControllers[newIndex] = TextEditingController( text: '这是第${newIndex + 1}行的自定义弹窗内容\n创建时间: ${DateTime.now().toString()}' ); }); } void _deleteRow(int index) { setState(() { rows.removeAt(index); editableControllers.removeAt(index).dispose(); // 删除对应的弹窗控制器 dialogControllers.remove(index)?.dispose(); dialogContents.remove(index); }); } // 编辑弹窗内容 void _editDialogContent(BuildContext context, int index) { showDialog( context: context, builder: (context) => StatefulBuilder( builder: (context, setState) { return AlertDialog( title: Text('编辑弹窗内容'), content: Container( width: MediaQuery.of(context).size.width * 0.8, height: MediaQuery.of(context).size.height * 0.5, child: TextField( controller: dialogControllers[index], maxLines: null, decoration: InputDecoration( border: OutlineInputBorder(), hintText: '输入自定义弹窗内容', ), ), ), actions: [ TextButton( child: Text('取消'), onPressed: () => Navigator.pop(context), ), TextButton( child: Text('保存'), onPressed: () { setState(() { dialogContents[index] = dialogControllers[index]!.text; }); Navigator.pop(context); }, ), ], ); }, ), ); } // 显示详情弹窗 void _showDetailDialog(BuildContext context, int index) { String content = dialogContents[index] ?? '这是第${index+1}行的自定义弹窗内容\n创建时间: ${DateTime.now().toString()}'; showDialog( context: context, builder: (context) => AlertDialog( title: Text('行详细信息'), content: SingleChildScrollView( child: Text( content, style: TextStyle(fontSize: 16), ), ), actions: [ TextButton( child: Text('编辑'), onPressed: () { Navigator.pop(context); _editDialogContent(context, index); }, ), TextButton( child: Text('关闭'), onPressed: () => Navigator.pop(context), ), ], ), ); } void _saveProject() { for (int i = 0; i < rows.length; i++) { rows[i].editableContent = editableControllers[i].text; } Navigator.pop(context, Project( name: projectNameController.text, rows: List.from(rows), dialogContents: dialogContents, )); } @override void dispose() { projectNameController.dispose(); for (var controller in editableControllers) { controller.dispose(); } for (var controller in dialogControllers.values) { controller.dispose(); } super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: TextField( controller: projectNameController, decoration: InputDecoration( hintText: '输入项目名称', border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 12), ), style: TextStyle(fontSize: 18, color: Colors.white), ), actions: [ IconButton( icon: Icon(Icons.save), onPressed: _saveProject, tooltip: '保存项目', ), ], ), body: SingleChildScrollView( scrollDirection: Axis.vertical, child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: DataTable( headingRowHeight: 48, dataRowHeight: 56, columns: const [ DataColumn(label: Text('固定内容', style: TextStyle(fontWeight: FontWeight.bold))), DataColumn(label: Text('可编辑内容', style: TextStyle(fontWeight: FontWeight.bold))), DataColumn(label: Text('操作', style: TextStyle(fontWeight: FontWeight.bold))), ], rows: List.generate(rows.length, (index) { return DataRow( cells: [ DataCell( Container( padding: EdgeInsets.symmetric(horizontal: 16), alignment: Alignment.centerLeft, child: Text( rows[index].fixedContent, style: TextStyle(color: Colors.grey[700]), ), ), ), DataCell( Padding( padding: EdgeInsets.symmetric(horizontal: 8), child: TextField( controller: editableControllers[index], decoration: InputDecoration( border: OutlineInputBorder(), contentPadding: EdgeInsets.symmetric(horizontal: 12), ), ), ), ), DataCell( Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: Icon(Icons.edit, color: Colors.blue), onPressed: () => _editDialogContent(context, index), tooltip: '编辑弹窗内容', ), IconButton( icon: Icon(Icons.info_outline, color: Colors.green), onPressed: () => _showDetailDialog(context, index), tooltip: '查看弹窗', ), SizedBox(width: 8), IconButton( icon: Icon(Icons.delete, color: Colors.red), onPressed: () => _deleteRow(index), tooltip: '删除行', ), ], ), ), ], ); }), ), ), ), floatingActionButton: FloatingActionButton( child: Icon(Icons.add), onPressed: _addNewRow, tooltip: '添加新行', ), ); } }将弹窗改为编程者提前设定的文字内容,且不可修改,每个按钮绑定不同的文字内容
11-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

talk_8

真诚赞赏,手有余香

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值