颤动问题:滚动时列表视图重建项目

Jak*_*sMD 8 flutter

当我滚动到列表视图的底部时,底部的项目被重建。当我滚动到顶部时,我的第一个项目被重建。第一个项目是一张带有可选择筹码的卡片,当发生这种情况时,这些筹码会被取消选中。并且“入口”动画也会重播。我怎么能阻止这个?

这是基本代码(它使用 simple_animations 包,我似乎无法用芯片重现问题,但我仍然有动画问题):

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final List _chips = ['Hello', 'World'];

  List _selected = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Issue demo'),
      ),
      body: ListView(
        children: <Widget>[
          FadeIn(
            1,
            Card(
              child: Wrap(
                spacing: 10,
                children: List<Widget>.generate(
                  _chips.length,
                  (int index) => InputChip(
                      label: Text(_chips[index]),
                      selected: _selected.contains(_chips[index]),
                      onSelected: (selected) {
                        setState(() {
                          if (selected) {
                            _selected.add(_chips[index]);
                          } else {
                            _selected.remove(_chips[index]);
                          }
                        });
                      }),
                ),
              ),
            ),
          ),
          FadeIn(1.5, Text('A', style: Theme.of(context).textTheme.display4)),
          FadeIn(2, Text('Very', style: Theme.of(context).textTheme.display4)),
          FadeIn(2.5, Text('Big', style: Theme.of(context).textTheme.display4)),
          FadeIn(3, Text('Scroll', style: Theme.of(context).textTheme.display4)),
          FadeIn(3.5, Text('View', style: Theme.of(context).textTheme.display4)),
          FadeIn(4, Text('With', style: Theme.of(context).textTheme.display4)),
          FadeIn(4.5, Text('Lots', style: Theme.of(context).textTheme.display4)),
          FadeIn(5, Text('Of', style: Theme.of(context).textTheme.display4)),
          FadeIn(5.5,Text('Items', style: Theme.of(context).textTheme.display4)),
          FadeIn(
            6,
            Card(
              child: Text('Last item',
                  style: Theme.of(context).textTheme.display2),
            ),
          ),
        ],
      ),
    );
  }
}

class FadeIn extends StatelessWidget {
  final double delay;
  final Widget child;

  FadeIn(this.delay, this.child);

  @override
  Widget build(BuildContext context) {
    final tween = MultiTrackTween([
      Track("opacity")
          .add(Duration(milliseconds: 500), Tween(begin: 0.0, end: 1.0)),
      Track("translateX").add(
          Duration(milliseconds: 500), Tween(begin: 130.0, end: 0.0),
          curve: Curves.easeOut)
    ]);

    return ControlledAnimation(
      delay: Duration(milliseconds: (300 * delay).round()),
      duration: tween.duration,
      tween: tween,
      child: child,
      builderWithChild: (context, child, animation) => Opacity(
        opacity: animation["opacity"],
        child: Transform.translate(
            offset: Offset(animation["translateX"], 0), child: child),
      ),
    );
  }
}

Run Code Online (Sandbox Code Playgroud)

你应该自己运行这个来完全理解这个问题

小智 18

要使 ListView 中的元素保持活动状态(回滚时不重新渲染),您应该使用参数addAutomaticKeepAlives: true. 并且 ListView 中的每个元素都必须是带有 AutomaticKeepAliveClientMixin 的 StatefulWidget。

这是我为您编辑的代码

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final List _chips = ['Hello', 'World'];

  List _selected = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Issue demo'),
      ),
      body: ListView(
        addAutomaticKeepAlives: true,
        children: <Widget>[
          FadeIn(
            1,
            Card(
              child: Wrap(
                spacing: 10,
                children: List<Widget>.generate(
                  _chips.length,
                  (int index) => InputChip(
                      label: Text(_chips[index]),
                      selected: _selected.contains(_chips[index]),
                      onSelected: (selected) {
                        setState(() {
                          if (selected) {
                            _selected.add(_chips[index]);
                          } else {
                            _selected.remove(_chips[index]);
                          }
                        });
                      }),
                ),
              ),
            ),
          ),
          FadeIn(1.5, Text('A', style: Theme.of(context).textTheme.display4)),
          FadeIn(2, Text('Very', style: Theme.of(context).textTheme.display4)),
          FadeIn(2.5, Text('Big', style: Theme.of(context).textTheme.display4)),
          FadeIn(3, Text('Scroll', style: Theme.of(context).textTheme.display4)),
          FadeIn(3.5, Text('View', style: Theme.of(context).textTheme.display4)),
          FadeIn(4, Text('With', style: Theme.of(context).textTheme.display4)),
          FadeIn(4.5, Text('Lots', style: Theme.of(context).textTheme.display4)),
          FadeIn(5, Text('Of', style: Theme.of(context).textTheme.display4)),
          FadeIn(5.5,Text('Items', style: Theme.of(context).textTheme.display4)),
          FadeIn(
            6,
            Card(
              child: Text('Last item',
                  style: Theme.of(context).textTheme.display2),
            ),
          ),
        ],
      ),
    );
  }
}

class FadeIn extends StatefulWidget {
  final double delay;
  final Widget child;
  FadeIn(this.delay, this.child);
  _FadeInState createState() => _FadeInState();
}

class _FadeInState extends State<FadeIn> with AutomaticKeepAliveClientMixin {

  @override
  Widget build(BuildContext context) {
    final tween = MultiTrackTween([
      Track("opacity")
          .add(Duration(milliseconds: 500), Tween(begin: 0.0, end: 1.0)),
      Track("translateX").add(
          Duration(milliseconds: 500), Tween(begin: 130.0, end: 0.0),
          curve: Curves.easeOut)
    ]);

    return ControlledAnimation(
      delay: Duration(milliseconds: (300 * widget.delay).round()),
      duration: tween.duration,
      tween: tween,
      child: widget.child,
      builderWithChild: (context, child, animation) => Opacity(
        opacity: animation["opacity"],
        child: Transform.translate(
            offset: Offset(animation["translateX"], 0), child: child),
      ),
    );
  }

  @override
  // TODO: implement wantKeepAlive
  bool get wantKeepAlive => true;
}
Run Code Online (Sandbox Code Playgroud)

  • 必须在 State.build 中调用 super.build 才能使用 AutomaticKeepAliveClientMixin。因此,在返回小部件之前添加此行:`super.build(context);` (5认同)
  • 嗨,伙计,我遇到了同样的问题,但使用 CustomScrollView 而不是 ListView...我已经尝试过此修复,但它不起作用...你能帮忙吗? (2认同)