5.2 优化列表加载功能
ListView小部件非常有用,上一节使用ListView并给它的children传递了一组小部件,这对于只有几条记录的列表很好,而且知道记录的数量不会太多,那么上一节的实现方式就足够了,但如果一个列表是动态添加的,并且无法预测数量,或者已经知道列表中有成千上万个元素,那么用上一节的方式创建就会非常低效,因为这种方式创建的列表,列表中的所有元素都会被渲染,那么有什么好方式呢?可以当需要显示列表中的一个元素时再渲染它,所以在向下滚动时,在当前元素后的下一个元素是需要被呈现的,在它进入视图之前立即渲染它,同时可以把滚动出视野的元素销毁,这是一种非常高级的编码方式,Flutter已实现这种方式渲染列表,因此不必自己编写代码。
Flutter能够自动销毁不需要再显示的内容,可以添加即将被显示的内容,这是非常高效的,不需要在内存中保留现在不需要看到的内容。我们可以使用ListView的builder构造器达到这种效果。builder构造器中没有children这个参数,builder构造器中使用的是另外两个参数,itemBuilder和itemCount。itemCount表示需要构建多少条记录,itemBuilder包含一个方法来定义构建什么样的小部件。方法中包含一组参数和一个方法体,可以使用匿名方法给itemBuilder赋值,也可以在类中创建一个方法,然后把方法引用赋值给itemBuilder。
我们使用第二种方式,在类中创建一个_buildNewItem()方法,代码如下:
以下画线开头的方法表示它只在这个类中使用,这是约定好的。这个方法可以返回一个小部件,表示构建一个什么样的记录,可以把构建Card的代码放到这里。代码如下:
_buildNewItem()在构建列表时被Flutter执行。itemBuilder不只是返回一个小部件,同时还需要使用两个参数,一个是context,它是BuildContext类型,之前我们在设置主题时使用过它;另一个是index,index是即将被构建的元素的索引,列表中的每一个元素都有索引,代表它在列表中的位置,index类型是int。通过index我们可以知道元素在列表中的位置。news是小部件中的一个属性,所以我们可以通过属性news[index]方式得到这个动态的元素,news[index]表示news列表中的某一条记录。news列表是string类型的数组,所以这里是一个string类型的内容,它将在屏幕上显示为文字。
这样我们就完成了itemBuilder()方法的编写,这个方法将构建每一条记录,但是我们需要知道它构建了多少条记录,这就需要使用itemCount参数了。构建属性news列表,列表有一个可以访问的属性length。news.length告诉这个列表中一共有多少条记录。设置好itemCount参数后,ListView.builder()将为我们做剩下的事情,它将根据指定的数量和_buildNewItem()方法构建列表。在_buildNewItem()方法中可以做任何事情,这个例子是从news列表中提取记录,并构建Card小部件。保存并重启后,我们不会意识到使用了另外一种高性能的方式来构建列表。这种方式对于很长的列表或者不知道有多长的列表非常高效。