簡體   English   中英

Flutter:ListView 在父更改后未重建 state

[英]Flutter: ListView not rebuilding after parent changes state

通過使用 ListView 我遇到了一個問題,我不明白發生了什么。 我得到了一個帶有任務列表的 ListView,第二個帶有 TaskTile 列表(構建方法中帶有 ListTile 的無狀態小部件)。

使用第一個 List i map 將任務放入 TaskTile,重建工作按預期進行,但在第二個列表中它僅在我滾動列表而不是 state 更改時工作。

這是兩個列表的代碼和代表問題的 gif:

import 'package:flutter/material.dart';
import 'package:todo/screens/task/task_screen.dart';

void main() {
 runApp(const MyApp());
}

class MyApp extends StatelessWidget {
 const MyApp({Key? key}) : super(key: key);

 @override
 Widget build(BuildContext context) {
   return MaterialApp(
     title: 'Flutter Demo',
     theme: ThemeData(
       primarySwatch: Colors.blue,
     ),
     home: const TaskScreen(),
   );
 } 
}

class Task {
 String title;
 bool completed;

 Task({required this.title, this.completed = false});

 void toggleCompleted() {
   completed = !completed;
 }
}

class TaskScreen extends StatefulWidget {
 const TaskScreen({Key? key}) : super(key: key);

 @override
 State<TaskScreen> createState() => _TaskScreenState();
}

class _TaskScreenState extends State<TaskScreen> {
 List<Task> tasks = [
   Task(title: "task1"),
   Task(title: "task2"),
   Task(title: "task3"),
 ];

 List<TaskTile> taskTiles = [
   TaskTile(task: Task(title: "tile1")),
   TaskTile(task: Task(title: "tile2")),
   TaskTile(task: Task(title: "tile3")),
 ];

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: const Text("Tasks"),
     ),
     body: SafeArea(
       child: Column(
         children: [
           Expanded(
               child: TasksList(
             tasks: tasks,
           )),
           const Divider(
             thickness: 10,
             color: Colors.blue,
           ),
           Expanded(
               child: TaskTilesList(
             tasks: taskTiles,
           )),
           Row(
             mainAxisAlignment: MainAxisAlignment.spaceEvenly,
             children: [
               ElevatedButton(
                   onPressed: () {
                     setState(() {
                       tasks.add(Task(title: "Task"));
                     });
                   },
                   child: const Text("Add Task")),
               ElevatedButton(
                   onPressed: () {
                     setState(() {
                       taskTiles.add(TaskTile(task: Task(title: "Tile")));
                     });
                   },
                   child: const Text("Add Task Tile")),
             ],
           ),
         ],
       ),
     ),
   );
 }
}

class TasksList extends StatelessWidget {
 const TasksList({Key? key, required this.tasks}) : super(key: key);

 final List<Task> tasks;

 @override
 Widget build(BuildContext context) {
   //************* List of Task mapped to TaskTile *******************
   return ListView(children: tasks.map((e) => TaskTile(task: e)).toList());
 }
}

class TaskTilesList extends StatelessWidget {
 const TaskTilesList({Key? key, required this.tasks}) : super(key: key);

 final List<TaskTile> tasks;

 @override
 Widget build(BuildContext context) {
   
   //************ List of TaskTile *************
   return ListView(
     children: tasks,
   );
 }
}

class TaskTile extends StatefulWidget {
 const TaskTile({Key? key, required this.task}) : super(key: key);

 final Task task;

 @override
 State<TaskTile> createState() => _TaskTileState();
}

class _TaskTileState extends State<TaskTile> {
 bool checkBoxValue = false;

 @override
 Widget build(BuildContext context) {
   print("Task: ${widget.task.title}");
   return ListTile(
     title: Text(
       widget.task.title,
       style: TextStyle(color: checkBoxValue ? Colors.black : Colors.black),
     ),
     trailing: TileCheckbox(
         checkBoxValue: checkBoxValue,
         callback: (val) {
           setState(() {
             checkBoxValue = val;
           });
         }),
     onTap: () {
       print("tile tapped");
       setState(() {});
     },
   );
 }
}

class TileCheckbox extends StatelessWidget {
 const TileCheckbox(
     {Key? key, required this.checkBoxValue, required this.callback})
     : super(key: key);

 final bool checkBoxValue;
 final Function callback;

 @override
 Widget build(BuildContext context) {
   return Checkbox(
     value: checkBoxValue,
     onChanged: (bool? value) {
       callback(value);
     },
   );
}
}

列表視圖錯誤

當我在有問題的列表中用 ListView.builder 替換 ListView 時,它可以工作,但我不明白為什么沒有構建器構造函數它就不能工作。 當我添加新的 TaskTile 時,我試圖通過打印來理解它,在控制台中,兩個列表正在重建,我什至可以看到新添加的 TaskTile,但它不會出現在 UI 中,而無需滾動列表。 它應該像這樣工作嗎? 傳遞 TaskTile 列表而不是映射的 TaskTile 列表時有什么區別?

根據定義,ListView 要求您一次創建所有項目,而構建器構造函數創建一個惰性列表,按需加載項目

來自官方文檔:

ListView:從顯式列表創建可滾動的線性小部件數組。 此構造函數適用於具有少量子項的列表視圖,因為構建 List 需要為可能顯示在列表視圖中的每個子項做工作,而不僅僅是那些實際可見的子項。

ListView.builder 創建一個可滾動的、按需創建的線性小部件陣列。 此構造函數適用於具有大量(或無限)子項的列表視圖,因為只為那些實際可見的子項調用構建器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM