Flutter ListView 在 Container Lazy Rendering 和性能上的表现

Flutter ListView in Container Lazy Rendering and performance

我有一长串经常更新的项目。该列表使用 ListView.builder 包裹在容器中以应用边框等呈现。

我的问题是,当 ListView 位于容器中时,会呈现所有项目,包括屏幕外的元素。由于列表经常重绘,严重影响性能。

我创建了两个例子来说明这个问题。为了简单起见,示例是无状态的,在现实生活中列表是有状态的。

示例 1 - ListView 是根小部件。请注意,在控制台中只构建了可见的卡片。 https://dartpad.dev/ac436b786ae48383c107a64bb3db8070

示例 2 - ListView 包装在容器中。注意所有卡片都已构建。 https://dartpad.dev/109f1f97085c1726c0826f6ea8b731ec

如何制作一个带有项目列表的可滚动容器,它只呈现可见项目?

示例2的来源:

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: SingleChildScrollView(
            child: Container(
                color: Colors.green,
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    Container(
                        width: 700,
                        decoration: BoxDecoration(
                            color: Colors.white,
                            borderRadius: BorderRadius.circular(10),
                            boxShadow: [
                              BoxShadow(
                                color: Colors.black.withOpacity(0.44),
                                spreadRadius: 0,
                                blurRadius: 15,
                                offset:
                                    Offset(0, 1), // changes position of shadow
                              ),
                            ]),
                        margin: EdgeInsets.all(24.0),
                        child: Container(
                            child: Column(
                                crossAxisAlignment: CrossAxisAlignment.stretch,
                                children: [
                              ListView.builder(
                                  scrollDirection: Axis.vertical,
                                  shrinkWrap: true,
                                  itemCount: 20,
                                  itemBuilder: (context, index) {
                                    var text = 'Card $index';
                                    print('Building card $text');
                                    return Card(
                                        child: Container(
                                            height: 130,
                                            child: Center(
                                              child: Text(text),
                                            )));
                                  })
                            ]))),
                  ],
                ))));
  }
}

你应该给包裹在容器中的listView一个高度限制。 就像这样:


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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: SingleChildScrollView(
            child: Container(
                color: Colors.green,
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    Container(
                        width: 700,
                        decoration: BoxDecoration(
                            color: Colors.white,
                            borderRadius: BorderRadius.circular(10),
                            boxShadow: [
                              BoxShadow(
                                color: Colors.black.withOpacity(0.44),
                                spreadRadius: 0,
                                blurRadius: 15,
                                offset:
                                Offset(0, 1), 
                              ),
                            ]),
                        margin: EdgeInsets.all(24.0),
                        child: Container(
                            child: Column(
                                crossAxisAlignment: CrossAxisAlignment.stretch,
                                children: [
                                  SizedBox( // add a SizedBox and set a specific height
                                    height: 1000,
                                    child: ListView.builder(
                                        scrollDirection: Axis.vertical,
                                        shrinkWrap: true,
                                        itemCount: 20,
                                        itemBuilder: (context, index) {
                                          var text = 'Card $index';
                                          print('testtest Building card $text');
                                          return Card(
                                              child: Container(
                                                  height: 130,
                                                  child: Center(
                                                    child: Text(text),
                                                  )));
                                        }),
                                  )
                                ]))),
                  ],
                ))));
  }
}