在这里插入图片描述

一、示例项目说明

本文配套的示例项目是一个待办事项应用,该页面完整展示了setState在实际应用中的使用场景,包括添加、标记完成、删除待办事项等功能。

二、setState核心概念

setState是StatefulWidget中更新状态的核心方法,它触发Widget的重建和UI的刷新。在示例项目中,所有的待办事项操作都通过setState来实现状态更新和UI刷新。

三、setState工作机制

添加待办

setState

加入队列

等待VSync

执行build

显示新列表

用户操作

调用_addTodo

标记State为dirty

Microtask队列

垂直同步信号

重新渲染UI

屏幕更新

阶段说明耗时
标记更新State对象标记为dirty<1μs
加入队列更新任务加入Microtask队列<5μs
VSync等待等待下一个垂直同步信号0-16ms
执行build重新执行build方法1-10ms
更新UI渲染新UI到屏幕1-5ms

四、示例代码分析

1. 完整的待办事项实现

class _Page04SetStateDemo extends StatefulWidget {
  const _Page04SetStateDemo();

  
  State<_Page04SetStateDemo> createState() => _Page04SetStateDemoState();
}

class _Page04SetStateDemoState extends State<_Page04SetStateDemo> {
  // 待办事项列表
  final List<String> _todos = [];
  
  // 文本输入控制器
  final TextEditingController _controller = TextEditingController();

  // 添加待办事项
  void _addTodo() {
    if (_controller.text.isNotEmpty) {
      setState(() {
        _todos.add(_controller.text);  // 添加新项
        _controller.clear();  // 清空输入框
      });
    }
  }

  // 标记待办事项完成/未完成
  void _toggleTodo(int index) {
    setState(() {
      if (_todos[index].startsWith('✓ ')) {
        _todos[index] = _todos[index].substring(2);  // 移除完成标记
      } else {
        _todos[index] = '✓ ${_todos[index]}';  // 添加完成标记
      }
    });
  }

  // 删除待办事项
  void _deleteTodo(int index) {
    setState(() {
      _todos.removeAt(index);  // 删除指定项
    });
  }

  
  Widget build(BuildContext context) {
    return Container(
      color: Colors.orange.shade50,
      child: SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(24),
          child: Column(
            children: [
              // 标题区域
              Container(
                padding: const EdgeInsets.all(20),
                decoration: BoxDecoration(
                  color: Colors.orange.shade600,
                  borderRadius: BorderRadius.circular(20),
                ),
                child: const Column(
                  children: [
                    Icon(Icons.checklist, size: 48, color: Colors.white),
                    SizedBox(height: 16),
                    Text(
                      '待办事项',
                      style: TextStyle(
                        fontSize: 28,
                        fontWeight: FontWeight.bold,
                        color: Colors.white,
                      ),
                    ),
                    SizedBox(height: 8),
                    Text(
                      'setState动态更新 - 页面 4/5',
                      style: TextStyle(
                        fontSize: 14,
                        color: Colors.white70,
                      ),
                    ),
                  ],
                ),
              ),
              const SizedBox(height: 24),
              // 待办事项内容区域
              Expanded(
                child: Container(
                  padding: const EdgeInsets.all(20),
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(16),
                    boxShadow: [
                      BoxShadow(
                        color: Colors.black.withOpacity(0.05),
                        blurRadius: 10,
                      ),
                    ],
                  ),
                  child: Column(
                    children: [
                      // 输入框和添加按钮
                      Row(
                        children: [
                          Expanded(
                            child: TextField(
                              controller: _controller,
                              decoration: InputDecoration(
                                hintText: '添加待办事项...',
                                filled: true,
                                fillColor: Colors.orange.shade50,
                                border: OutlineInputBorder(
                                  borderRadius: BorderRadius.circular(12),
                                  borderSide: BorderSide.none,
                                ),
                                contentPadding: const EdgeInsets.symmetric(
                                  horizontal: 16,
                                  vertical: 16,
                                ),
                              ),
                            ),
                          ),
                          const SizedBox(width: 12),
                          Container(
                            decoration: BoxDecoration(
                              color: Colors.orange.shade600,
                              borderRadius: BorderRadius.circular(12),
                            ),
                            child: IconButton(
                              onPressed: _addTodo,
                              icon: const Icon(Icons.add, color: Colors.white, size: 28),
                            ),
                          ),
                        ],
                      ),
                      const SizedBox(height: 20),
                      // 待办事项列表
                      Expanded(
                        child: _todos.isEmpty
                            ? Center(
                                child: Column(
                                  mainAxisAlignment: MainAxisAlignment.center,
                                  children: [
                                    Icon(
                                      Icons.inbox,
                                      size: 64,
                                      color: Colors.grey.shade300,
                                    ),
                                    const SizedBox(height: 16),
                                    Text(
                                      '暂无待办事项',
                                      style: TextStyle(
                                        color: Colors.grey.shade500,
                                        fontSize: 16,
                                      ),
                                    ),
                                  ],
                                ),
                              )
                            : ListView.builder(
                                itemCount: _todos.length,
                                itemBuilder: (context, index) {
                                  final todo = _todos[index];
                                  final isCompleted = todo.startsWith('✓ ');
                                  final displayTodo = isCompleted ? todo.substring(2) : todo;

                                  return Dismissible(
                                    key: Key('$index'),
                                    onDismissed: (_) => _deleteTodo(index),
                                    child: Container(
                                      margin: const EdgeInsets.only(bottom: 12),
                                      padding: const EdgeInsets.all(16),
                                      decoration: BoxDecoration(
                                        color: isCompleted
                                            ? Colors.green.shade50
                                            : Colors.orange.shade50,
                                        borderRadius: BorderRadius.circular(12),
                                        border: Border.all(
                                          color: isCompleted
                                              ? Colors.green.shade200
                                              : Colors.orange.shade200,
                                        ),
                                      ),
                                      child: Row(
                                        children: [
                                          // 完成标记按钮
                                          InkWell(
                                            onTap: () => _toggleTodo(index),
                                            child: Container(
                                              width: 28,
                                              height: 28,
                                              decoration: BoxDecoration(
                                                color: isCompleted
                                                    ? Colors.green.shade600
                                                    : Colors.orange.shade300,
                                                borderRadius: BorderRadius.circular(8),
                                              ),
                                              child: Icon(
                                                isCompleted
                                                    ? Icons.check
                                                    : Icons.circle_outlined,
                                                color: Colors.white,
                                                size: 18,
                                              ),
                                            ),
                                          ),
                                          const SizedBox(width: 12),
                                          // 待办事项文本
                                          Expanded(
                                            child: Text(
                                              displayTodo,
                                              style: TextStyle(
                                                fontSize: 16,
                                                decoration: isCompleted
                                                    ? TextDecoration.lineThrough
                                                    : null,
                                                color: isCompleted
                                                    ? Colors.grey.shade600
                                                    : Colors.black87,
                                              ),
                                            ),
                                          ),
                                        ],
                                      ),
                                    ),
                                  );
                                },
                              ),
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  
  void dispose() {
    _controller.dispose();  // 清理TextEditingController
    super.dispose();
  }
}

五、setState使用场景

1. 单个状态更新

// 示例:添加单个待办事项
void _addTodo() {
  setState(() {
    _todos.add(_controller.text);  // 只更新列表
  });
}

2. 批量状态更新

// 示例:添加并清空输入框
void _addTodo() {
  setState(() {
    _todos.add(_controller.text);  // 更新列表
    _controller.clear();  // 更新输入框
  });
}

3. 条件状态更新

// 示例:切换完成状态
void _toggleTodo(int index) {
  setState(() {
    if (_todos[index].startsWith('✓ ')) {
      _todos[index] = _todos[index].substring(2);  // 取消完成
    } else {
      _todos[index] = '✓ ${_todos[index]}';  // 标记完成
    }
  });
}

4. 删除操作

// 示例:删除待办事项
void _deleteTodo(int index) {
  setState(() {
    _todos.removeAt(index);  // 删除指定项
  });
}

六、setState与异步操作

1. 异步加载待办事项

Future<void> _loadTodos() async {
  setState(() => _isLoading = true);
  try {
    final todos = await fetchTodosFromApi();
    if (mounted) {
      setState(() {
        _todos.addAll(todos);
        _isLoading = false;
      });
    }
  } catch (e) {
    if (mounted) {
      setState(() {
        _error = '加载失败';
        _isLoading = false;
      });
    }
  }
}

2. 搜索过滤

Future<void> _searchTodos(String query) async {
  if (query.isEmpty) {
    setState(() {
      _filteredTodos = _todos;
    });
    return;
  }
  
  final results = await searchTodos(query);
  if (mounted) {
    setState(() {
      _filteredTodos = results;
    });
  }
}

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐