“This is the 9th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

preface

ListView is the most common component in an application, and lists are often loaded with many elements. When there are too many elements, especially when the image file is large, the list may become stuck, and in serious cases, the application may crash. This article describes how to optimize lists.

Optimization point 1: Use Builder to build lists

When your list elements are growing dynamically (such as pulling up to load more), don’t just keep adding components to the children array like children, because that would be bad.

// Bad usage
ListView(
  children: [
    item1,
    item2,
    item3,
    ...
  ],
)

// Correct usage
ListView.builder(
  itemBuilder: (context, index) => ListItem(),
  itemCount: itemCount,
)
Copy the code

For listView. builder, the list elements are built on demand, meaning that only those visible elements are called to itemBuilder to build the elements, thus reducing the performance overhead for large lists.

Creates a scrollable, linear array of widgets that are created on demand. This constructor is appropriate for list views with a large (or infinite) number of children because the builder is called only for those children that are actually visible.

Optimization point 2: Disable the addAutomaticKeepAlives and addRepaintBoundaries features

Both of these attributes are designed to optimize the user experience during scrolling. The addAutomaticKeepAlives feature defaults to true, meaning that the state of list elements can be kept after they are invisible, allowing for a quick build when they appear on screen again. This is a way of trading space for time and incurs a certain amount of memory overhead. You can turn this feature off by setting it to false. The downside is that if you swipe too fast, you can get a brief white screen (which rarely happens).

AddRepaintBoundaries are boundaries that enclose the list elements with a Repaint Boundary so that scrolling is not redrawn. If the list is easy to draw (if the layout of the list elements is simple), you can turn this feature off to improve scrolling fluency.

addAutomaticKeepAlives: false,
addRepaintBoundaries: false.Copy the code

Optimization point 3: Wherever possible, use const decorations for components that are immutable within a list element

Using const is like caching elements for sharing. If some parts of a list element remain the same, we can use const.

return Padding(
  child: Row(
    children: [
      const ListImage(),
      const SizedBox(
        width: 5.0,
      ),
      Text('the first$indexElements'),
    ],
  ),
  padding: EdgeInsets.all(10.0));Copy the code

Optimization point 4: Use itemExtent to determine the size of the scrolling direction of list elements

For many lists, the scrolling dimension is known in advance from the UI design. If this is known, using the itemExtent attribute to specify the scrolling dimension of the list element can improve performance. This is because, if not specified, you will need to calculate the size of each element in the scrolling direction during scrolling, consuming computational resources.

itemExtent: 120.Copy the code

Optimize the instance

Below is a list of the original unmodified, well, garbage code.

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

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

class _LargeListViewState extends State<LargeListView> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Big list'),
        brightness: Brightness.dark,
      ),
      body: ListView(
        children: List.generate(
          1000,
          (index) => Padding(
            padding: EdgeInsets.all(10.0),
            child: Row(
              children: [
                Image.network(
                  'https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7869eac08a7d4177b600dc7d64998204~tplv-k3u1fbpfcp-watermark.jpeg',
                  width: 200,),const SizedBox(
                  width: 5.0,
                ),
                Text('the first$indexElements'),],),),),),); }}Copy the code

Of course, you don’t actually use list. generate to generate List elements, ** But you also don’t use a List

List object to keep adding List elements to it as the **children of the ListView! The modified code is shown below, with more code but much better performance because the list elements are broken down into finer pieces.

import 'package:flutter/material.dart';

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

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

class _LargeListViewState extends State<LargeListView> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Big list'),
        brightness: Brightness.dark,
      ),
      body: ListView.builder(
        itemBuilder: (context, index) => ListItem(
          index: index,
        ),
        itemCount: 1000,
        addAutomaticKeepAlives: false,
        addRepaintBoundaries: false,
        itemExtent: 120.0,),); }}class ListItem extends StatelessWidget {
  final int index;
  ListItem({Key? key, required this.index}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Padding(
      child: Row(
        children: [
          const ListImage(),
          const SizedBox(
            width: 5.0,
          ),
          Text('the first$indexElements'),
        ],
      ),
      padding: EdgeInsets.all(10.0)); }}class ListImage extends StatelessWidget {
  const ListImage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Image.network(
      'https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7869eac08a7d4177b600dc7d64998204~tplv-k3u1fbpfcp-watermark.jpeg',
      width: 200,); }}Copy the code

conclusion

This article introduces four practical optimizations for Flutter ListView. In fact, these points can be found in the documentation on the official website. Therefore, if you encounter performance problems, it is recommended to look at official documentation in addition to search engines. In addition, for list pictures, sometimes the front and back ends also need to cooperate, for example, the current mobile phones are known as 100 million pixels, if you upload the original picture directly, then loading such a large picture will definitely consume resources. In this case, the recommendation is to generate list thumbnails (you may need to generate different thumbnails for different screen sizes, such as the article header for digging gold, in several resolutions).

I am dao Code Farmer with the same name as my wechat official account. This is a column about the introduction and practice of Flutter, providing systematic learning articles about Flutter. See the corresponding source code here: The source code of Flutter Introduction and Practical column. If you have any questions, please add me to the wechat account: island-coder. If you feel you have something to gain, please give three pairs of love as follows:

๐Ÿ‘๐Ÿป : a praise to encourage!

๐ŸŒŸ : Collect articles, easy to look back!

๐Ÿ’ฌ : Comment exchange, mutual progress!