【问题标题】:Flutter ListView wrong State matching for StatefulWidget itemsFlutter ListView 对 StatefulWidget 项的状态匹配错误
【发布时间】:2021-07-20 02:57:12
【问题描述】:

我正在使用 ListView,当它的项目为 StatefulWidget 时遇到了问题。

例如,每个小部件都有自己的countdownTime 保存在其状态中。当我向列表中插入第一个新小部件时,新的 State 属于错误的小部件(它必须属于第一个而不是最后一个项目)。似乎 deactivate-dispose 状态匹配过程有问题。我尝试向它们添加key,但它在处理并重新创建所有小部件项目时表现得很奇怪,导致所有倒计时重置。

我花了 2 天时间研究更多关于 StatefulWidget 和 ListView 的信息,但我无能为力。

我在这里创建了 Dartpad,如果我做错了什么,请看看。 Dartpad to the example

非常感谢!

【问题讨论】:

  • _MyStatefulState 中删除color 并将其添加到MyStatefulWidget,类似于:class MyStatefulWidget extends StatefulWidget { final color = generateRandomColor(); ...
  • 谢谢。我知道当我们交换小部件位置时状态非常敏感,在这种情况下它可能不匹配,但是有没有办法可以在不将颜色移出状态的情况下解决这个问题?
  • 看来我的例子太简单了,因为我在 State 中使用了颜色常量。我已经更改了 Dartpad 中的代码,实际上是 State 包含变量属性,例如 countdownTime。虽然我在第一个位置添加了新的小部件,但实际上它重用了错误的状态
  • 你说的不清楚。请进一步解释。

标签: flutter dart


【解决方案1】:

你必须使用AutomaticKeepAliveClientMixin-mixin

AutomaticKeepAliveClientMixin 混合添加到 StateState(项目小部件)中,覆盖 wantKeepAlive 方法并返回 true

我解决了什么:

  • 新项目将添加到列表顶部。
  • 滚动后保持状态

你的完整(更新)飞镖:

import 'dart:async';

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, this.title}) : super(key: key);

  final String? title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List<Widget> _widgets = [MyStatefulWidget()];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView.separated(
        itemCount: _widgets.length,
        itemBuilder: (_, index) {
          return _widgets[index];
        },
        reverse: true,
        shrinkWrap: true,
        separatorBuilder: (BuildContext context, int index) {
          return SizedBox(
            width: 5,
          );
        },
      ),
      floatingActionButton: TextButton(
        onPressed: () {
          setState(() {
            // Insert first in the list, hope it's just need to rebuild only the first item, the remains are unchanged
            _widgets.add(MyStatefulWidget());
          });
        },
        child: Container(
          child: Text(
            'Press',
            style: TextStyle(
              color: Colors.white,
              fontSize: 24,
            ),
          ),
          padding: EdgeInsets.all(10),
          decoration: BoxDecoration(
            color: Colors.red,
          ),
        ),
      ),
    );
  }
}

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

  @override
  State<StatefulWidget> createState() {
    print('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> createState');
    return _MyStatefulState();
  }
}

+class _MyStatefulState extends State<MyStatefulWidget> with AutomaticKeepAliveClientMixin{
  StreamSubscription? countdownSubscription;
  int countdownTime = 30;

   @override
   bool get wantKeepAlive => true;
  
  @override
  void initState() {
    super.initState();
    initTimeoutUI();
  }

  void initTimeoutUI() {
    countdownSubscription = Future.delayed(Duration(seconds: 1)).asStream().listen((value) {
      if (countdownTime > 0) {
        setState(() {
          countdownTime--;
        });
      }
      initTimeoutUI();
    });
  }

  @override
  void dispose() {
    super.dispose();
    countdownSubscription?.cancel();
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Container(
      width: 100,
      height: 100,
      child: Center(child: Text('countdown: $countdownTime')),
    );
  }
}

【讨论】:

  • 谢谢!你拯救了我艰难的日子。有效!我检查并看到reverse: true, shrinkWrap: true, 用于将项目添加到列表顶部,对吗?和 AutomaticKeepAliveClientMixin 在长时间滚动后保持状态?如果列表太长,我还没有检查状态会发生什么,但正如你所说,如果我从列表的开头滚动到结尾,某些状态会丢失,对吧?
  • 其实不是,我解决的是我写的。即使长滚动也会自动保持。你必须尝试一次。如果您觉得有用,请点赞并接受答案。
猜你喜欢
  • 1970-01-01
  • 2019-10-09
  • 2020-12-18
  • 2018-07-06
  • 1970-01-01
  • 2018-12-21
  • 1970-01-01
  • 1970-01-01
  • 2021-07-01
相关资源
最近更新 更多