1. 下拉刷新需要用到RefreshIndicator组件,为属性onRefresh设置下拉时触发的方法即可
    2. 上拉加载关键是用ListView的控制器来实现
      1. // 1. 定义滑动控制器变量
      2. ScrollController _msgCtrl = ScrollController();
      3. // 2. 在初始化勾子中添加下拉监听
      4. @override
      5. void initState() {
      6. super.initState();
      7. _msgCtrl.addListener(() {
      8. if (_msgCtrl.position.pixels == _msgCtrl.position.maxScrollExtent) { // 下拉触发条件
      9. _loadMore();
      10. }
      11. });
      12. }
      13. // 3. 在ListView中使用
      14. ListView.builder(
      15. itemCount: msgData.length + 1,
      16. physics: const AlwaysScrollableScrollPhysics(),
      17. controller: _msgCtrl,
      18. itemBuilder: (context, index) {
      19. if (index == msgData.length) {
      20. return loadMoreBottom(hasMore);
      21. } else {
      22. return msgItem(msgData[index]);
      23. }
      24. },
      25. )

    完整代码如下:

    1. import 'package:flutter/material.dart';
    2. import 'package:annotation_route/route.dart';
    3. import 'package:doctor_admin/config/common.dart';
    4. import 'package:doctor_admin/route/route.dart';
    5. @ARoute(url: 'page://myMsg/myMsg')
    6. class MyMsg extends StatefulWidget {
    7. final dynamic option;
    8. MyMsg(this.option);
    9. MyMsgState createState() => MyMsgState();
    10. }
    11. class MyMsgState extends State<MyMsg> {
    12. int page = 0;
    13. List msgData = [];
    14. bool hasMore = true, isLoading = false;
    15. ScrollController _msgCtrl = ScrollController();
    16. Future _loadMore() async{
    17. if(isLoading || !hasMore) return;
    18. setState(() {
    19. isLoading = true;
    20. });
    21. List newMsgs;
    22. page++;
    23. final res = await request(context, '/api/news/news_list', 'GET', params: {'page': page, 'size': 10});
    24. setState(() {
    25. isLoading = false;
    26. });
    27. if(res == null) return;
    28. hasMore = res.data['data']['hasNextPage'];
    29. newMsgs = res.data['data']['list'];
    30. printWrapped(newMsgs.toString());
    31. if(page > 1) {
    32. msgData.addAll(newMsgs);
    33. }else {
    34. msgData = newMsgs;
    35. }
    36. setState(() {
    37. page = page;
    38. hasMore = hasMore;
    39. // msgData = result;
    40. });
    41. }
    42. Future _refresh() async {
    43. if(isLoading) return;
    44. // msgData.clear();
    45. setState(() {
    46. page = 0;
    47. hasMore = true;
    48. });
    49. await _loadMore();
    50. }
    51. String getSimpleText(html){
    52. var re1 = new RegExp("<.+?>");//匹配html标签的正则表达式,"g"是搜索匹配多个符合的内容
    53. var msg = html.replaceAll(re1,'');//执行替换成空字符
    54. return msg;
    55. }
    56. @override
    57. void initState() {
    58. super.initState();
    59. _loadMore();
    60. _msgCtrl.addListener(() {
    61. if (_msgCtrl.position.pixels == _msgCtrl.position.maxScrollExtent) {
    62. _loadMore();
    63. }
    64. });
    65. }
    66. Widget msgItem(item) {
    67. return ClickView(
    68. onTap: () {
    69. Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context){
    70. return AppRoute.getPage('page://myMsg/myMsgDetail', {'msgId': item['id']});
    71. }));
    72. },
    73. margin: EdgeInsets.only(top: setSize(20)),
    74. color: Colors.white,
    75. radius: setSize(8),
    76. child: Container(
    77. height: setSize(200),
    78. padding: EdgeInsets.fromLTRB(setSize(18), setSize(20), setSize(20), setSize(18)),
    79. child: Column(
    80. mainAxisAlignment: MainAxisAlignment.spaceBetween,
    81. crossAxisAlignment: CrossAxisAlignment.center,
    82. children: <Widget>[
    83. Text(item['createTime'], style: TextStyle(color: Color(0xffcccccc), fontSize: setFont(22), fontWeight: FontWeight.w400, height: 15/11),),
    84. Row(
    85. mainAxisAlignment: MainAxisAlignment.spaceBetween,
    86. crossAxisAlignment: CrossAxisAlignment.center,
    87. children: <Widget>[
    88. Container(
    89. width: setSize(564),
    90. height: setSize(84),
    91. child: Column(
    92. mainAxisAlignment: MainAxisAlignment.spaceBetween,
    93. crossAxisAlignment: CrossAxisAlignment.start,
    94. children: <Widget>[
    95. Padding(
    96. padding: EdgeInsets.only(left: setSize(22)),
    97. child: Text(item['title'], style: TextStyle(color: Color(0xff4a4a4a), fontSize: setFont(28), fontWeight: FontWeight.w500, height: 20/14), maxLines: 1, overflow: TextOverflow.ellipsis,),
    98. ),
    99. Row(
    100. mainAxisAlignment: MainAxisAlignment.spaceBetween,
    101. crossAxisAlignment: CrossAxisAlignment.center,
    102. children: <Widget>[
    103. Container(
    104. width: setSize(14),
    105. height: setSize(14),
    106. decoration: BoxDecoration(
    107. borderRadius: BorderRadius.circular(setSize(7)),
    108. color: Colors.transparent
    109. ),
    110. ),
    111. SizedBox(width: setSize(10),),
    112. Expanded(
    113. child: Text(getSimpleText(item['content']), style: TextStyle(color: Color(0xff666666), fontSize: setFont(22), fontWeight: FontWeight.w500, height: 16/11), maxLines: 1, overflow: TextOverflow.ellipsis,),
    114. )
    115. ],
    116. )
    117. ],
    118. ),
    119. ),
    120. nextPageArr()
    121. ],
    122. )
    123. ],
    124. ),
    125. ),
    126. );
    127. }
    128. @override
    129. Widget build(BuildContext context) {
    130. return Scaffold(
    131. appBar: AppBar(
    132. centerTitle: true,
    133. title: Text('我的消息', style: TextStyle(color: Color(0xff4a4a4a), fontSize: setFont(32), fontWeight: FontWeight.w500)),
    134. leading: goBackArr(context, isBlack: true),
    135. elevation: 0,
    136. ),
    137. body: Container(
    138. width: setFullWidth(context),
    139. height: setFullHeight(context),
    140. padding: EdgeInsets.symmetric(vertical: 0, horizontal: setSize(32)),
    141. color: Color(0xffF9F9F9),
    142. child: RefreshIndicator(
    143. onRefresh: _refresh,
    144. child: msgData.length > 0 ? ListView.builder(
    145. itemCount: msgData.length + 1,
    146. physics: const AlwaysScrollableScrollPhysics(),
    147. controller: _msgCtrl,
    148. itemBuilder: (context, index) {
    149. if (index == msgData.length) {
    150. return loadMoreBottom(hasMore);
    151. } else {
    152. return msgItem(msgData[index]);
    153. }
    154. },
    155. ) : (isLoading ?
    156. LoadingView(context: context,) :
    157. blankView(context, getAssetImage('blank_msg.png'), '暂无消息哦~'))
    158. ),
    159. )
    160. );
    161. }
    162. }