RefreshIndicator 是下拉刷新指示器, 包装一个可滚动widget

    示例:

    1. import 'package:flutter/material.dart';
    2. class HomePage extends StatefulWidget {
    3. @override
    4. createState() => new _HomePageState();
    5. }
    6. class _HomePageState extends State<HomePage> {
    7. var list = [];
    8. int page = 0;
    9. bool isLoading = false; // 是否正在请求新数据
    10. bool showMore = false; // 是否显示底部加载中提示
    11. bool offState = false; // 是否显示进入页面时的圆形进度条
    12. ScrollController scrollController = ScrollController();
    13. @override
    14. void initState() {
    15. super.initState();
    16. // 监听滚动事件
    17. scrollController.addListener(() {
    18. // 是否滑动到了最底部: 当前位置为滚动的最大高度
    19. if (scrollController.position.pixels ==
    20. scrollController.position.maxScrollExtent) {
    21. setState(() {
    22. showMore = true;
    23. });
    24. getMoreData();
    25. }
    26. });
    27. getListData();
    28. }
    29. @override
    30. Widget build(BuildContext context) {
    31. return MaterialApp(
    32. home: Scaffold(
    33. appBar: AppBar(
    34. title: Text("RefreshIndicator"),
    35. ),
    36. body: Stack(
    37. children: <Widget>[
    38. RefreshIndicator(
    39. child: ListView.builder(
    40. controller: scrollController,
    41. itemCount: list.length + 1,//列表长度+底部加载中提示
    42. itemBuilder: choiceItemWidget,
    43. ),
    44. onRefresh: _onRefresh,
    45. ),
    46. Offstage(
    47. offstage: offState,
    48. child: Center(
    49. child: CircularProgressIndicator(),
    50. ),
    51. ),
    52. ],
    53. )
    54. ),
    55. );
    56. }
    57. @override
    58. void dispose() {
    59. super.dispose();
    60. // 手动停止滑动监听
    61. scrollController.dispose();
    62. }
    63. // 加载列表行组件
    64. Widget choiceItemWidget(BuildContext context, int position) {
    65. if (position < list.length) {
    66. return HomeListItem(position, list[position], (position) {
    67. debugPrint("点击了第$position条");
    68. });
    69. } else if (showMore) {
    70. return showMoreLoadingWidget();
    71. } else {
    72. return null;
    73. }
    74. }
    75. // 加载更多提示组件
    76. Widget showMoreLoadingWidget() {
    77. return Container(
    78. height: 50.0,
    79. child: Row(
    80. mainAxisAlignment: MainAxisAlignment.center,
    81. crossAxisAlignment: CrossAxisAlignment.center,
    82. children: <Widget>[
    83. Text('加载中...', style: TextStyle(fontSize: 16.0),),
    84. ],
    85. ),
    86. );
    87. }
    88. // 模拟进入页面获取数据
    89. void getListData() async {
    90. if (isLoading) {
    91. return;
    92. }
    93. setState(() {
    94. isLoading = true;
    95. });
    96. await Future.delayed(Duration(milliseconds: 300), () {
    97. setState(() {
    98. isLoading = false;
    99. offState = true;
    100. list = List.generate(20, (i) {
    101. return ItemInfo("ListView的一行数据$i");
    102. });
    103. });
    104. });
    105. }
    106. // 模拟到底部加载更多数据
    107. void getMoreData() async {
    108. if (isLoading) {
    109. return;
    110. }
    111. setState(() {
    112. isLoading = true;
    113. page++;
    114. });
    115. await Future.delayed(Duration(milliseconds: 300), () {
    116. setState(() {
    117. isLoading = false;
    118. showMore = false;
    119. list.addAll(List.generate(3, (i) {
    120. return ItemInfo("上拉添加 $page : $i");
    121. }));
    122. });
    123. });
    124. }
    125. // 模拟下拉刷新
    126. Future<void> _onRefresh() async {
    127. if (isLoading) {
    128. return;
    129. }
    130. setState(() {
    131. isLoading = true;
    132. page = 0;
    133. });
    134. await Future.delayed(Duration(milliseconds: 300), () {
    135. setState(() {
    136. isLoading = false;
    137. List tempList = List.generate(3, (i) {
    138. return ItemInfo("下拉添加 $page : $i");
    139. });
    140. tempList.addAll(list);
    141. list = tempList;
    142. });
    143. });
    144. }
    145. }
    146. class ItemInfo {
    147. String title;
    148. ItemInfo(this.title);
    149. }
    150. // 定义一个回调接口
    151. typedef OnItemClickListener = void Function(int position);
    152. // ignore: must_be_immutable
    153. class HomeListItem extends StatelessWidget {
    154. int position;
    155. ItemInfo iteminfo;
    156. OnItemClickListener listener;
    157. HomeListItem(this.position, this.iteminfo, this.listener);
    158. @override
    159. Widget build(BuildContext context) {
    160. var widget = Column(
    161. children: <Widget>[
    162. Container(
    163. child: Column(
    164. children: <Widget>[
    165. Row(
    166. children: <Widget>[
    167. Text(
    168. iteminfo.title,
    169. style: TextStyle(
    170. fontSize: 15.0,
    171. color: Color(0xff999999),
    172. ),
    173. )
    174. ],
    175. ),
    176. ],
    177. mainAxisAlignment: MainAxisAlignment.center,
    178. ),
    179. height: 50.0,
    180. padding: EdgeInsets.only(left: 20.0),
    181. ),
    182. // 分割线
    183. Container(
    184. height: 1.0,
    185. color: Color.fromARGB(255, 230, 230, 230),
    186. )
    187. ],
    188. );
    189. // InkWell点击的时候有水波纹效果
    190. return InkWell(
    191. onTap: () => listener(position),
    192. child: widget
    193. );
    194. }
    195. }

    效果:
    019.gif