flutter使用getx做一个todolist

如图最终效果:

实现步骤:

一、创建基础文件

创建test_controller.dart、test_binding.dart、test_view.dart、index.dart文件,分别对应逻辑层、依赖注入层、视图层、模块入口

复制代码
路由跳转 → TestBinding 初始化 TestController → TestView 获取控制器并渲染 UI  
→ 用户操作触发 Controller 方法 → Controller 更新状态 → Obx 驱动 UI 刷新  
→ 页面关闭 → GetX 销毁 Controller 并调用 onClose()  
(全程通过 index.dart 简化外部引用)
Dart 复制代码
//test_binding.dart文件代码
import 'package:app3/views/test/test_controller.dart';
import 'package:get/get.dart';

class TestBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => TestController());
  }
}
Dart 复制代码
//index.dart代码
export 'test_binding.dart';
export 'test_controller.dart';
export 'test_view.dart';

二、test_controller.dart中写状态、增删改查方法

Dart 复制代码
//test_controller.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';

class TestController extends GetxController {
  @override
  void onInit() {
    super.onInit();
    print('初始化生命周期函数:$todoList');
    
    // 使用 ever 监听 todoList 的变化
    ever(todoList, (newValue) {
      print("todoList 变化了,新值:$newValue");
    });
  }

  @override
  void onReady() {
    super.onReady();
    print('UI 首次构建完成:$todoList');
  }

  @override
  void onClose() {
    super.onClose();
    print('页面关闭:$todoList');
  }

  final RxList<Map<String, dynamic>> todoList = <Map<String, dynamic>>[
    {'title': '吃饭', 'isDone': true},
    {'title': '睡觉', 'isDone': false},
    {'title': '打游戏', 'isDone': false},
    {'title': '学习', 'isDone': false},
    {'title': '看电影', 'isDone': false},
    {'title': '看小说', 'isDone': false},
  ].obs;

  void add(Map<String, dynamic> item) {
    todoList.add(item);
  }

  void delete(int index) {
    todoList.removeAt(index);
  }

  void showDeleteDialog(int index) {
    Get.dialog(
      AlertDialog(
        title: const Text('确定要删除吗?'),
        content: const Text('删除后将无法恢复'),
        actions: [
          TextButton(
              onPressed: () {
                Get.back();
              },
              child: const Text('取消')),
          TextButton(
              onPressed: () {
                delete(index);
                Get.back();
              },
              child: const Text('确定')),
        ],
      ),
    );
  }
  void showAddDialog() {
    final TextEditingController textController = TextEditingController();

    Get.dialog(
      AlertDialog(
        title: const Text('添加待办事项'),
        content: TextField(
          controller: textController,
          decoration: const InputDecoration(
            hintText: '请输入标题',
            border: OutlineInputBorder(),
          ),
          autofocus: true,
        ),
        actions: [
          TextButton(
              onPressed: () {
                Get.back();
              },
              child: const Text('取消')),
          TextButton(
              onPressed: () {
                if (textController.text.trim().isNotEmpty) {
                  add({'title': textController.text.trim(), 'isDone': false});
                  Get.back();
                }
              },
              child: const Text('确定')),
        ],
      ),
    );
  }

  void finish(int index) {
    todoList[index]['isDone'] = !todoList[index]['isDone'];
    todoList.refresh(); // 手动触发更新
  }
}

三、test_view.dart文件视图渲染

Dart 复制代码
import 'package:app3/views/test/test_controller.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

class TestView extends GetView<TestController> {
  const TestView({super.key});
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: const Text('todolist')),
        body: Column(
          children: [
            Expanded(
              child: Obx(() => ListView.builder(
                itemCount: controller.todoList.length,
                // 构建每个列表项
                itemBuilder: (BuildContext context, int index) {
                  return ListTile(
                    leading: Checkbox(
                      value: controller.todoList[index]['isDone'], 
                      onChanged: (value) {
                        controller.finish(index);
                      }
                    ),
                    title: Text(
                      '${controller.todoList[index]['title']}',
                      style: TextStyle(
                        decoration: controller.todoList[index]['isDone'] 
                          ? TextDecoration.lineThrough 
                          : TextDecoration.none,
                        color: controller.todoList[index]['isDone']
                          ? Colors.grey
                          : null,
                      ),
                    ),
                    subtitle: Text('这是第${index + 1}个条目'),
                    trailing: IconButton(
                      onPressed: () {
                        controller.showDeleteDialog(index);
                      }, 
                      icon: const Icon(Icons.delete)
                    ),
                  );
                },
              )),
            )
          ],
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            controller.showAddDialog();
          },
          child: const Icon(Icons.add),
        ),
    );
  }
}
相关推荐
m0_739030005 小时前
springboot中的怎么用JUnit进行测试的?
junit·1024程序员节
街尾杂货店&5 小时前
webpack - 常用的 CSS 加载器(webpack与其常见loader加载器使用方式)
1024程序员节
海域云赵从友6 小时前
中国企业跨境云组网指南:低延迟访问德国AWS云做数据分析的实操方案
1024程序员节
可涵不会debug6 小时前
依托金仓数据库的医疗信创多院区实践与 KingbaseES 操作详解
1024程序员节
电话交换机IPPBX-3CX6 小时前
电话交换机软件3CX安全访问实践:屏蔽IP访问,仅允许域名访问
安全·域名·ippbx·1024程序员节·电话交换机
從南走到北6 小时前
场馆预定系统小程序
1024程序员节
十里-6 小时前
使用 Quill 实现编辑器功能
1024程序员节
2301_780356706 小时前
物联网数据中台智慧医院企业厂家——全视通
1024程序员节