Flutter 状态 ListView.Builder 和 Column 的子元素之间不同的行为

问题描述 投票:0回答:1

在观看 Flutter 中的 Keys 教程后,我尝试改编一些示例:https://www.youtube.com/watch?v=kn0EOS-ZiIc

尽管我使用的是 uniqueKey(),但在使用 ListView.Builder 布局图块时,每次都会为两个交换的小部件元素创建状态对象。如果我使用一列来显示小部件,它确实会保留状态。除了不同的 UI 元素之外,代码是相同的。这是 MRE:

import 'dart:math';

import 'package:flutter/material.dart';

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

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

  @override
  State<MainApp> createState() => _MainAppState();
}

class _MainAppState extends State<MainApp> {
  late List<Widget> tiles;

  @override
  void initState() {
    super.initState();
    tiles = [
      ColorTile(key: UniqueKey()),
      ColorTile(key: UniqueKey()),
      ColorTile(key: UniqueKey()),
    ];
  }

  @override
  Widget build(BuildContext context) {
    print('build outside');
    return MaterialApp(
      home: Scaffold(
        floatingActionButton: FloatingActionButton(onPressed: swapTiles),
        /* body: Column(
          children: tiles,
        ), */
        body: ListView.builder(
          itemCount: tiles.length,
          itemBuilder: (context, index) {
            return tiles[index];
          },
        ),
      ),
    );
  }

  void swapTiles() {
    setState(() {
      tiles.insert(2, tiles.removeAt(1));
    });
  }
}

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

  @override
  State<ColorTile> createState() => _ColorTileState();
}

class _ColorTileState extends State<ColorTile> {
  final Color color = Colors.primaries[Random().nextInt(Colors.primaries.length)];

  @override
  Widget build(BuildContext context) {
    print("build ColorTile..., key: ${widget.key}");
    return Container(
      width: 100,
      height: 100,
      color: color,
    );
  }
}

根据我能找到的所有信息,如果 widgettype 和 key 相同,那么 Flutter 不会处理元素树上的状态对象。然而,对于 ListView.builder 来说,每次按下交换按钮时似乎都会创建一个新的状态对象。

这是为什么?

Dart SDK版本:3.0.3(稳定), Flutter 3.10.3 • 通道稳定

flutter dart widget
1个回答
0
投票

所有图块的状态保持一致,但每次调用

setState
时,都会对其应用新的随机颜色。要解决此问题,您可以从 Tile 小部件类中提取
Colors
并将它们传递给构造函数。这样,随机颜色只会在执行
parent widget
时生成一次。如果您在交换图块时调用
setState
,则不会影响颜色状态。

示例如下:

    import 'dart:math';

import 'package:flutter/material.dart';

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

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

  @override
  State<MainApp> createState() => _MainAppState();
}

class _MainAppState extends State<MainApp> {
  late List<Widget> tiles;

  @override
  void initState() {
    super.initState();

    tiles = [
      ColorTile(  color:   Colors.primaries[Random().nextInt(Colors.primaries.length)],
  key: UniqueKey()),
      ColorTile(color:   Colors.primaries[Random().nextInt(Colors.primaries.length)], key: UniqueKey()),
      ColorTile(color:   Colors.primaries[Random().nextInt(Colors.primaries.length)], key: UniqueKey()),
    ];
  }

  @override
  Widget build(BuildContext context) {
    print('build outside');
    return MaterialApp(
      home: Scaffold(
        floatingActionButton: FloatingActionButton(onPressed: swapTiles),
        /* body: Column(
          children: tiles,
        ), */
        body: ListView.builder(
          itemCount: tiles.length,
          itemBuilder: (context, index) {
            return tiles[index];
          },
        ),
      ),
    );
  }

  void swapTiles() {
    setState(() {
      tiles.insert(2, tiles.removeAt(1));
    });
  }
}

class ColorTile extends StatefulWidget {
  const ColorTile({required this.color,super.key});
final Color color;
  @override
  State<ColorTile> createState() => _ColorTileState();
}

class _ColorTileState extends State<ColorTile> {

  @override
  Widget build(BuildContext context) {
    print("build ColorTile..., key: ${widget.key}");
    return Container(
      width: 100,
      height: 100,
      color:widget. color,
    );
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.