A scrollable list of widgets arranged linearly.
ListView is the most commonly used scrolling widget. It displays its children one after another in the scroll direction. In the cross axis, the children are required to fill the ListView.
If non-null, the itemExtent forces the children to have the given extent in the scroll direction.
If non-null, the prototypeItem forces the children to have the same extent as the given widget in the scroll direction.
Specifying an itemExtent or an prototypeItem is more efficient than letting the children determine their own extent because the scrolling machinery can make use of the foreknowledge of the children's extent to save work, for example when the scroll position changes drastically.
You can't specify both itemExtent and prototypeItem, only one or none of them.
class ExListView extends StatelessWidget {
const ExListView({super.key});
@override
Widget build(BuildContext context) {
return ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
color: Color(Random().nextInt(0xffffff)).withOpacity(1),
child: Center(
child: Text('Entry $index'),
),
);
},
);
}
}
There are four options for constructing a ListView:
- The default constructor takes an explicit List of children. This constructor is appropriate for list views with a small number of children because constructing the List requires doing work for every child that could possibly be displayed in the list view instead of just those children that are actually visible.
- The ListView.builder constructor takes an IndexedWidgetBuilder, which builds the children 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.
- The ListView.separated constructor takes two IndexedWidgetBuilders:
itemBuilder
builds child items on demand, andseparatorBuilder
similarly builds separator children which appear in between the child items. This constructor is appropriate for list views with a fixed number of children. - The ListView.custom constructor takes a SliverChildDelegate, which provides the ability to customize additional aspects of the child model. For example, a SliverChildDelegate can control the algorithm used to estimate the size of children that are not actually visible.
ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
color: Color(Random().nextInt(0xffffff)).withOpacity(1),
child: Center(
child: Text('Entry $index'),
),
);
},
separatorBuilder: (context, index) => Divider(
color: Colors.red,
),
)
With Header1
@override
Widget build(BuildContext context) {
return Column(children: <Widget>[
ListTile(title:Text("Header")),
Expanded(
child: ListView.builder(itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text("$index"));
}),
),
]);
}
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
import 'package:flutter/rendering.dart';
class InfiniteListView extends StatefulWidget {
@override
_InfiniteListViewState createState() => _InfiniteListViewState();
}
class _InfiniteListViewState extends State<InfiniteListView> {
static const loadingTag = "##loading##"; // tailing loading text
var _words = <String>[loadingTag];
@override
void initState() {
super.initState();
_retrieveData();
}
@override
Widget build(BuildContext context) {
return ListView.separated(
itemCount: _words.length,
itemBuilder: (context, index) {
//如果到了表尾
if (_words[index] == loadingTag) {
//不足100条,继续获取数据
if (_words.length - 1 < 100) {
//获取数据
_retrieveData();
//加载时显示loading
return Container(
padding: const EdgeInsets.all(16.0),
alignment: Alignment.center,
child: SizedBox(
width: 24.0,
height: 24.0,
child: CircularProgressIndicator(strokeWidth: 2.0),
),
);
} else {
//已经加载了100条数据,不再获取数据。
return Container(
alignment: Alignment.center,
padding: EdgeInsets.all(16.0),
child: Text(
"没有更多了",
style: TextStyle(color: Colors.grey),
),
);
}
}
//显示单词列表项
return ListTile(title: Text(_words[index]));
},
separatorBuilder: (context, index) => Divider(height: .0),
);
}
void _retrieveData() {
Future.delayed(Duration(seconds: 2)).then((e) {
setState(() {
//重新构建列表
_words.insertAll(
_words.length - 1,
//每次生成20个单词
generateWordPairs().take(20).map((e) => e.asPascalCase).toList(),
);
});
});
}
}