简单的Flutter列表视图滚动不流畅

8
我一直在评估Flutter是否适用于应用程序,并从一个非常简单的文本列表示例开始。在构建了这个第一个视图之后,我注意到列表视图滚动不流畅,因此我仔细查看了展示应用程序,结果发现例如Reflectly是一个美丽的应用程序,但它也存在同样的问题-只有一个简单的文本列表却出现了非常卡顿的滚动。到目前为止,我已经在iOS模拟器,iPhone XR,三星Galaxy Android设备和Android Pixel 2 XL模拟器上确认了这一点。
我没有看到关于这个问题的讨论,所以我想知道我是否做错了什么,但也怀疑我的例子如此简单,而Reflectly也有相同的问题。
我希望社区能够理解: 1.我是否明显地做错了什么导致这种情况? 2.如果您在您的设备上运行,您是否看到与我相同的情况? 3.这是否已知并将得到解决?如果我承诺使用Flutter,我是否可以放心,在不久的将来我的列表将平稳滚动?
以下是您可以运行以重现此问题的代码(抱歉,它有点牵强,但我想尝试各种Flutter / Dart功能):
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'My List',
        home: Scaffold(
          appBar: AppBar(
            title: Text('My List'),
            backgroundColor: Color.fromRGBO(255, 0, 0, 0.9),
          ),
          body: Padding(
            padding: EdgeInsets.all(16.0),
            child: Column(
            children: [
              Expanded(child: TimeSelector()),
            ],
          )),
        ));
  }
}

abstract class ListItem {}

class TimeHeader implements ListItem {
  final String header;

  TimeHeader(this.header);
}

class TimeOption implements ListItem {
  final String timeString;
  final String meridian;

  TimeOption(this.timeString, this.meridian);
}

final List<ListItem> litems = [
  TimeHeader("Morning"),
  TimeOption("10:00", "am"),
  TimeOption("10:30", "am"),
  TimeOption("11:30", "am"),
  TimeHeader("Afternoon"),
  TimeOption("1:00", "pm"),
  TimeOption("1:30", "pm"),
  TimeOption("2:30", "pm"),
  TimeHeader("Night"),
  TimeOption("5:30", "pm"),
  TimeOption("6:30", "pm"),
  TimeOption("7:30", "pm"),
  TimeOption("8:30", "pm"),
  TimeOption("9:30", "pm"),
  TimeOption("10:30", "pm"),
  TimeOption("11:30", "pm"),
  TimeOption("11:45", "pm"),
  TimeOption("11:49", "pm"),
];

class TimeSelector extends StatelessWidget {
  final _headerFont = new TextStyle(fontWeight: FontWeight.w600, fontSize: 13.0, color: Color.fromRGBO(164, 164, 164, 1));
  final _smallerFont = const TextStyle(fontSize: 12.0);

  @override
  ListView build(BuildContext context) {
    return new ListView.builder(
      padding: const EdgeInsets.all(16.0),
      itemCount: litems.length,
      itemBuilder: (BuildContext ctxt, int index) => _buildItem(ctxt, index),
    );
  }

  Widget _buildItem(BuildContext ctxt, int index) {
    final item = litems[index];

    if (item is TimeHeader) {
      return new ListTile(
        title: Text(
          item.header,
          style: _headerFont,
        ),
      );
    } else if (item is TimeOption) {
      return new ListTile(
        title: Text(
          item.timeString + item.meridian.toUpperCase(),
          style: _smallerFont,
        ),
      );
    } else {
      return new Text("UNKNOWN");
    }
  }
}

1
"Choppy" 的意思是指滚动不流畅,会出现微小的跳跃。你必须仔细观察才能注意到,在 iPhone/iOS 模拟器上更为明显。如果缓慢滚动,你会感觉好像跳过了一些帧。 - Tony
你在发布模式下吗? - Raouf Rahiche
2
你的代码在发布模式下应该能够正常工作。 - pskink
嗯,它的表现确实好多了!感谢你指出这一点。 - Tony
我也遇到了同样的问题。有没有办法只在调试模式下解决这个问题?@RaoufRahiche - Rishabh
显示剩余7条评论
3个回答

8

Flutter ListView在调试模式下滚动时确实存在问题。尽管您的代码在发布模式下可以正常运行,滚动也不会有任何延迟。但是,如果您想在调试模式下无延迟地滚动,则可以选择在ListView上使用SingleChildScrollView。只需将您的滚动小部件放入一个列中,并将该列作为SingleChildScrollView的子代。 在您的情况下,您正在使用ListView.builder。我建议您使用以下代码来实现非常平滑的滚动:

@override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Flexible(
            child: ListView.builder(
              shrinkWrap: true,
              physics: NeverScrollableScrollPhysics(),
              padding: const EdgeInsets.all(16.0),
              itemCount: litems.length,
              itemBuilder: (BuildContext ctxt, int index) => _buildItem(ctxt, index),
            ),
          )
        ],
      ),
    );
  }

别忘了使用 mainAxisSize: MainAxisSize.min 作为列大小以及 shrinkWrap: truephysics: NeverScrollableScrollPhysics()

physics: NeverScrollableScrollPhysics() 将禁用您的 ListView.builder 的滚动功能,您将体验到列表的非常流畅的滚动。


3
虽然这个解决方案很好,但是它的缺点在于性能,因为整个列表一次性渲染。因此我们可以在应用程序中清楚地看到滞后。简单来说,它增加了加载时间。 - Muhammad Tameem Rafay

2

如果您正在处理非常少的静态数据列表项,可以使用addAutomaticKeepAlives: true来加速列表。

最初的回答:

如果您正在处理动态数据或具有大量列表项的静态数据,则应该考虑使用更高级的技术来提高列表性能。


0
我成功解决了iOS上的卡顿滚动问题,方法是禁用Impeller渲染后端。
要在iOS上禁用Impeller,请在应用的Info.plist文件的顶级标签下添加以下标签。
<key>FLTEnableImpeller</key>
<false />

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接