flutter 尝试解决顶部添加数据,滑动列表会跳转到顶部的问题

参考文章
代码地址
参考文章

正在做一个小说的滑动列表功能,拉上一章内容,往列表第一位插入数据时,滑动列表跳到了顶部。
下面是参考代码

import 'package:flutter/material.dart';
import 'dart:math' as math;

///聊天列表,添加旧数据和新数据的时候不会导致列表跳动,首尾添加数据不会抖动
class ChatListScrollDemoPage2 extends StatefulWidget {
  const ChatListScrollDemoPage2({Key? key}) : super(key: key);

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

class _ChatListScrollDemoPageState2 extends State<ChatListScrollDemoPage2> {
  List<ItemData> newData = [
    new ItemData(txt: "*********init 1*********", type: "Right"),
    new ItemData(txt: "*********init 2*********", type: "Right"),
    new ItemData(txt: "*********init 3*********", type: "Right")
  ];
  List<ItemData> loadMoreData = [];

  var centerKey = GlobalKey();
  var scroller = ScrollController();
  final random = math.Random(10);
  double extentAfter = 0;

  renderRightItem(ItemData data) {
    var height =  random.nextInt(60);
    return Container(
      height: 50 + height.toDouble(),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(4),
        color: Colors.red,
      ),
      margin: EdgeInsets.only(left: 50, right: 10, top: 5, bottom: 5),
      padding: EdgeInsets.all(10),
      alignment: Alignment.centerRight,
      child: new Text(
        data.txt,
        maxLines: 10,
      ),
    );
  }

  renderLeftItem(ItemData data) {
    var height =  random.nextInt(60);
    return Container(
      height: 50 + height.toDouble(),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(4),
        color: Colors.green,
      ),
      margin: EdgeInsets.only(right: 50, left: 10, top: 5, bottom: 5),
      padding: EdgeInsets.all(10),
      alignment: Alignment.centerLeft,
      child: new Text(
        data.txt,
        maxLines: 10,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          newData.add(ItemData(
              txt: "#### new Send ${newData.length} #### #### #### #### ",
              type: "Right"));
          setState(() {});
          Future.delayed(Duration(milliseconds: 1000), () {
            scroller.jumpTo(scroller.position.maxScrollExtent);
          });
        },
        child: Text(
          "Send",
          style: TextStyle(color: Colors.yellow),
        ),
      ),
      appBar: AppBar(
        title: new Text("ControllerDemoPage"),
        actions: [
          new TextButton.icon(
              onPressed: () {
                final random = math.Random();
                int randomInt = random.nextInt(10);
                for (int i = 0; i < 20; i++) {
                  var type = randomInt + i;
                  if (type % 4 == 0) {
                    loadMoreData.add(ItemData(
                        txt: "--------Old ${loadMoreData.length}$i",
                        type: "Right"));
                  } else {
                    loadMoreData.add(ItemData(
                        txt: "---------Old ${loadMoreData.length}$i",
                        type: "Left"));
                  }
                }
                setState(() {});
              },
              icon: Icon(
                Icons.add,
                color: Colors.red,
              ),
              label: Text(
                "add old",
                style: TextStyle(color: Colors.red),
              )),
          new TextButton.icon(
              onPressed: () {
                final random = math.Random();
                int randomInt = random.nextInt(10);
                for (int i = 0; i < 20; i++) {
                  var type = randomInt + i * 3;
                  if (type % 4 == 0) {
                    newData.add(ItemData(
                        txt: "##########  New ${newData.length} $i",
                        type: "Left"));
                  } else {
                    newData.add(ItemData(
                        txt: "##########   New ${newData.length} $i",
                        type: "Right"));
                  }
                }
                setState(() {});
                if (extentAfter == 0) {
                  ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                    content: Text("你目前位于最底部,自动跳转新消息item"),
                    duration: Duration(milliseconds: 1000),
                  ));
                  Future.delayed(Duration(milliseconds: 200), () {
                    scroller.jumpTo(scroller.position.maxScrollExtent);
                    Future.delayed(Duration(milliseconds: 400), () {
                      scroller.jumpTo(scroller.position.maxScrollExtent);
                    });
                  });
                } else {
                  ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                    content: InkWell(
                      onTap: () {
                        scroller.jumpTo(scroller.position.maxScrollExtent);
                      },
                      child: Container(
                        height: 50,
                        width: 200,
                        color: Colors.blueAccent,
                        alignment: Alignment.centerLeft,
                        child: Text("点击我自动跳转新消息item"),
                      ),
                    ),
                    duration: Duration(milliseconds: 1000),
                  ));
                }
              },
              icon: Icon(
                Icons.add,
                color: Colors.yellow,
              ),
              label: Text(
                "add new",
                style: TextStyle(color: Colors.yellow),
              )),

          ///先加载一页满的数据 然后再拉一页老数据
          ///相当于两个sliverlist都有数据
          ///然后对底下的sliverlist删除数据 就会出现底下空白
          ///这里测试删除时,用偏移来解决底部空白
          // new TextButton.icon(
          //     onPressed: () {
          //       newData.removeLast();
          //       newData.removeLast();
          //       newData.removeLast();
          //       newData.removeLast();
          //       newData.removeLast();
          //
          //       newData.insert(0, loadMoreData[0]);
          //       newData.insert(0,loadMoreData[1]);
          //       newData.insert(0,loadMoreData[2]);
          //       newData.insert(0,loadMoreData[4]);
          //       newData.insert(0,loadMoreData[5]);
          //
          //       loadMoreData.removeAt(0);
          //       loadMoreData.removeAt(1);
          //       loadMoreData.removeAt(2);
          //       loadMoreData.removeAt(3);
          //       loadMoreData.removeAt(4);
          //
          //       setState(() {
          //
          //       });
          //
          //
          //     },
          //     icon: Icon(
          //       Icons.delete,
          //       color: Colors.yellow,
          //     ),
          //     label: Text(
          //       "Delete",
          //       style: TextStyle(color: Colors.yellow),
          //     )),
        ],
      ),
      extendBody: true,
      body: NotificationListener(
        onNotification: (notification) {
          if (notification is ScrollNotification) {
            if (notification.metrics is PageMetrics) {
              return false;
            }
            if (notification.metrics is FixedScrollMetrics) {
              if (notification.metrics.axisDirection == AxisDirection.left ||
                  notification.metrics.axisDirection == AxisDirection.right) {
                return false;
              }
            }
            extentAfter = notification.metrics.extentAfter;
          }
          return false;
        },
        child: CustomScrollView(
          controller: scroller,
          center: centerKey,
          slivers: [
            SliverList(
              delegate: SliverChildBuilderDelegate(
                    (BuildContext context, int index) {
                  var item = loadMoreData[index];
                  if (item.type == "Right")
                    return renderRightItem(item);
                  else
                    return renderLeftItem(item);
                },
                childCount: loadMoreData.length,
              ),
            ),
            SliverPadding(
              padding: EdgeInsets.zero,
              key: centerKey,
            ),
            SliverList(
              delegate: SliverChildBuilderDelegate(
                    (BuildContext context, int index) {
                  var item = newData[index];
                  if (item.type == "Right")
                    return renderRightItem(item);
                  else
                    return renderLeftItem(item);
                },
                childCount: newData.length,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class ItemData {
  String txt = "";
  String type = "";

  ItemData({
    required this.txt,
    required this.type,
  });
}

//小说滑动列表代码,往上滑的时候跳转到顶部,处理:跳回到上一个位置,缺点是会闪一下

import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:loading_indicator/loading_indicator.dart';
import 'package:social_im/pages/read_book/buy_novel_dialog.dart';
import '../../common/Global.dart';
import '../../common/colors.dart';
import '../../common/globalEventBus.dart';
import '../../config/shared_preferences_helper.dart';
import '../../http/api.dart';
import '../../http/net_callback.dart';
import '../../http/rxhttp.dart';
import '../../http/utils/NetUtils.dart';
import '../../http/utils/response.dart';
import 'novelModel/novel_chapter_content.dart';
import 'novelModel/novel_details_model.dart';
import 'novelModel/save_novel_data.dart';

//小说阅读页
class ReadPageView extends StatefulWidget {
  ChapterInfo? chapterInfo;
  String? novelName;

  ReadPageView(this.chapterInfo, this.novelName, {Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() => ReadPageViewState();
}

class ReadPageViewState extends State<ReadPageView>{
  //列表控制器
  final ScrollController _scrollController = ScrollController();

  //还有更多数据
  bool hasMore = true;

  //上划的章数
  int startPage = 0;

  //最开始的章数
  int firstPage = 0;

  //下滑的章数
  int endPage = 0;

  //点击的位置
  late Offset startPosition;

  //顶部布局的高度
  final GlobalKey _globalKey = GlobalKey();
  //数据列表的高度
  GlobalKey listGlobalKey = GlobalKey();
  //数据列表的高度小于满屏高度减顶部高度时,填充一个占位高度,确保可以滑动
  double seatHeight = 0.0;

  //是否显示占位符
  bool showSeat = false;

  //小说内容列表
  List<ChapterInfo> novelChapterContentList = [];

  //扣费弹窗已弹出,不可以再弹出来了
  StreamSubscription<NovelDialogHasShow>? novelDialogHasShowEvent;

  //已显示小说扣费弹窗
  bool hasShowNovelFreeDialog = false;

  //是否显示底部loading
  bool showLoading = false;

  //是否正在进行网络请求
  bool hasHttpRes = false;

  ///一秒内只监听列表滑动一次划到低部,防止多次请求
  bool scrollListener = false;

  @override
  void initState() {
    //扣费弹窗已弹出来,不可以再弹了
    novelDialogHasShowEvent = EventBusUtil.listen((event) {
      if (event.hasShow) {
        hasShowNovelFreeDialog = true;
      } else {
        hasShowNovelFreeDialog = false;
      }
    });
    //显示loading
    showLoading = true;
    //获取小说数据
    getNovelData(widget.chapterInfo?.bookId ?? 1,
        widget.chapterInfo?.chapter ?? 1, false,
        initGetData: true);
    //标记最开始的章节
    startPage = widget.chapterInfo?.chapter ?? 1;
    if (startPage >= 2) {
      //上一章的章节数等于传进来的章节数减一
      startPage = startPage - 1;
    }
    //标记最末尾的章节
    endPage = widget.chapterInfo?.chapter ?? 1;

    // 监听滚动事件:注意:请求数据的时候不可能让页数+1了
    //拉到最底部,请求下一章数据
    _scrollController.addListener(() {
      //防止一次监听到两次滑到最底部
      if (scrollListener == false) {
        if (_scrollController.position.pixels ==
            _scrollController.position.maxScrollExtent) {
          //已经拉到一次底部了
          scrollListener = true;
          //达到最大滚动位置
          if (hasMore) {
            mySetState(() {
              //显示loading
              showLoading = true;
              //不是往顶部添加数据
              bool start = false;
              //要在添加数据之前跳转,不然就会出现,添加数据完成后直接跳到末尾了
              if (_scrollController.hasClients) {
                _scrollController
                    .jumpTo(_scrollController.position.maxScrollExtent - 1);
              }
              //请求数据
                getNovelData(widget.chapterInfo?.bookId ?? 1, endPage, start);
            });
          }

          //延时一秒才可以再监听滑到底部
          Future.delayed(const Duration(milliseconds: 1000), () {
            scrollListener = false;
          });
        }
      }else{
        if (_scrollController.position.pixels ==
            _scrollController.position.maxScrollExtent){
          if (_scrollController.hasClients) {
            _scrollController
                .jumpTo(_scrollController.position.maxScrollExtent - 1);
          }
        }
      }

      //拉到最顶部,请求上一章
      if (_scrollController.position.pixels ==
          _scrollController.position.minScrollExtent) {
        if (getListHeight() != null) {
          //(一进来的数据就满屏)列表的高度大于屏幕高度,才往上挪一下
          if (getListHeight()! > Global.screenHeight) {
            if (_scrollController.hasClients) {
              _scrollController
                  .jumpTo(_scrollController.position.minScrollExtent + 1);
            }
          } else if (getListHeight()! + seatHeight > Global.screenHeight) {
            //(一进来的数据没满屏),列表的高度+填充高度大于满屏就网上挪一下
            if (showSeat == true) {
              if (_scrollController.hasClients) {
                _scrollController
                    .jumpTo(_scrollController.position.minScrollExtent + 1);
              }
            }
          }
        }

        //往顶部添加数据
        bool start = true;
        //大于等于第一章才请求
        if (hasMore) {
          mySetState(() {
            if (startPage >= 1) {
              getNovelData(widget.chapterInfo?.bookId ?? 1, startPage, start);
            }
          });
        }
      }
    });

    super.initState();
  }

  mySetState(callBack) {
    if (mounted) {
      setState(() {
        callBack();
      });
    }
  }

  //获取小说具体内容
  getNovelData(int bookId, int chapter, bool isStart, {bool? initGetData}) {
    RxHttp<Response>()
      ..init()
      ..setBaseUrl(Api.BUSINESS_BASE_API)
      ..setPath(Api.API_BOOK_CONTENT)
      ..setCacheMode(CacheMode.FIRST_CACHE_THEN_REQUEST)
      ..setJsonTransFrom((p0) => Response.fromJson(json.decoder.convert(p0)))
      ..setParams({
        "book_id": bookId,
        "chapter": chapter,
      })
      ..call(
          NetCallback(onNetFinish: (response) {
            //加延时防止滑动列表短时间重复请求
            if (response.code == 0 || response.code == 200) {
              //为false就处理数据
              log('小说数据11112 ${json.encode(response.data)}');
              NovelChapterContent? novelChapterContent =
                  NovelChapterContent.fromJson(response.data);
              handleNovel(novelChapterContent, isStart, initGetData);
              if (mounted) {
                setState(() {});
              }
            }
          }, onCacheFinish: (response) {
            if (response.code == 0 || response.code == 200) {
              NovelChapterContent? novelChapterContent =
                  NovelChapterContent.fromJson(response.data);
              log('小说数据1111 ${json.encode(response.data)}');
              //如果该章节需要扣费,且还没有购买,就不执行
              if (novelChapterContent.chapterInfo != null) {
                if (novelChapterContent.chapterInfo!.freeChapter != null) {
                  //免费的就让缓存执行
                  if (novelChapterContent.chapterInfo!.freeChapter == 1) {
                    handleNovel(novelChapterContent, isStart, initGetData);
                  } else {
                    //收费但是已经购买的可以让缓存执行
                    if (novelChapterContent.chapterInfo!.isBuy != null) {
                      //已经购买
                      if (novelChapterContent.chapterInfo!.isBuy == 1) {
                        handleNovel(novelChapterContent, isStart, initGetData);
                      }
                    }
                  }
                }
              }
              if (mounted) {
                setState(() {});
              }
            }
          }, onNetError: (errorCode, error) {
            showLoading = false;
            mySetState(() {});
            // showToast('$error ($errorCode)');
          }),
          server: Servers.businessServer);
  }

  //点进去需要扣费,缓存需要扣费,购买过小说后再请求一次,刷新缓存,免得进来还是先拿缓存还要扣费
  reGetNovelData(int bookId, int chapter) {
    if (chapter <= 0) {
      return;
    }
    RxHttp<Response>()
      ..init()
      ..setBaseUrl(Api.BUSINESS_BASE_API)
      ..setPath(Api.API_BOOK_CONTENT)
      ..setCacheMode(CacheMode.REQUEST_FAILED_READ_CACHE)
      ..setJsonTransFrom((p0) => Response.fromJson(json.decoder.convert(p0)))
      ..setParams({
        "book_id": bookId,
        "chapter": chapter,
      })
      ..call(
          NetCallback(
              onNetFinish: (response) {},
              onCacheFinish: (response) {},
              onNetError: (errorCode, error) {}),
          server: Servers.businessServer);
  }

  //添加数据时,查找当前列表是否有重复数据
  checkListData(NovelChapterContent? novelChapterContent) {
    bool isHasData = false;
    if (novelChapterContent != null) {
      if (novelChapterContent.chapterInfo != null) {
        for (int i = 0; i < novelChapterContentList.length; i++) {
          if (novelChapterContentList[i].bookId ==
              novelChapterContent.chapterInfo!.bookId) {
            if (novelChapterContentList[i].chapter ==
                novelChapterContent.chapterInfo!.chapter) {
              isHasData = true;
            }
          }
        }
      }
    }
    return isHasData;
  }

  //处理小说扣费
  //添加数据时检查列表是否够满屏,没满屏的话显示控件
  handleNovel(
      NovelChapterContent? novelChapterContent, bool isStart, bool? getData) {
    showLoading = false;
    if (novelChapterContent != null) {
      if (novelChapterContent.chapterInfo != null) {
        //contains去重
        if (!novelChapterContentList
            .contains(novelChapterContent.chapterInfo)) {
          //遍历去重,其实应该要删掉旧的数据(缓存),添加新的数据(网络)
          if (checkListData(novelChapterContent) == false) {
            if (isStart) {
              //往顶部插入数据
              //不免费章节
              if (novelChapterContent.chapterInfo!.freeChapter == 2) {
                //判断是否已购买
                if (novelChapterContent.chapterInfo!.isBuy == 2) {
                  //已经弹出扣费弹窗了,就不再弹
                  if (hasShowNovelFreeDialog) {
                  } else {
                    showModalBottomSheet(
                        shape: const RoundedRectangleBorder(
                            borderRadius: BorderRadius.only(
                                topLeft: Radius.circular(24),
                                topRight: Radius.circular(24))),
                        isScrollControlled: true,
                        enableDrag: false,
                        backgroundColor: CommonColors.getColorF5F8F5,
                        context: context,
                        builder: (context) =>
                            BuyNovelDialog(novelChapterContent)).then((value) {
                      if (value != null) {
                        if (value == true) {
                          double extentAfter =
                              _scrollController.position.extentAfter;
                          if (checkListData(novelChapterContent) == false) {
                            novelChapterContentList.insert(
                                0, novelChapterContent.chapterInfo!);
                            startPage = startPage - 1;
                          }
                          Future.delayed(const Duration(milliseconds: 100), () {
                            if (_scrollController.position.maxScrollExtent -
                                    extentAfter <
                                Global.screenHeight) {
                              //插入数据后跳转到上一章的底部,衔接阅读
                              if (_scrollController.hasClients) {
                                //+1防止跳到顶部又请求上一章了
                                _scrollController.jumpTo(
                                    _scrollController.position.minScrollExtent+1);
                              }
                            } else {
                              if (_scrollController.hasClients) {
                                _scrollController.jumpTo(
                                    _scrollController.position.maxScrollExtent -
                                        extentAfter -
                                        Global.screenHeight +
                                        (Global.topHeight + 30 + 20));
                              }
                            }
                          });
                          //重新请求一下数据,刷新缓存数据
                          reGetNovelData(
                              widget.chapterInfo?.bookId ?? 1, startPage + 1);
                          //删除原来的记录,保存新的记录,查询
                          deleteOldUserIdAndChapter(novelChapterContent);
                          savaUserIdAndChapter(novelChapterContent);
                          checkNovelData(novelChapterContent);
                          mySetState(() {});
                          Future.delayed(const Duration(milliseconds: 100), () {
                            addDataCheckScreen();
                          });
                        }
                      } else {
                        //不购买章节,划到顶部页数就-1了,实际上因为弹窗问题,数据没添加到,所以要把页数加回来
                      }
                    });
                  }
                } else {
                  //已购买过章节
                  double extentAfter = _scrollController.position.extentAfter;
                  novelChapterContentList.insert(
                      0, novelChapterContent.chapterInfo!);
                  startPage = startPage - 1;
                  Future.delayed(const Duration(milliseconds: 100), () {
                    //跳转的时候减了extentAfter,还要判断剩余屏幕高度是否大于Global.screenHeight,不大于就直接跳到最开始位置,大于就跳到下面到公式
                    if (_scrollController.position.maxScrollExtent -
                            extentAfter <
                        Global.screenHeight) {
                      if (_scrollController.hasClients) {
                        //+1防止跳到顶部又请求上一章了
                        _scrollController
                            .jumpTo(_scrollController.position.minScrollExtent+1);
                      }
                    } else {
                      if (_scrollController.hasClients) {
                        _scrollController.jumpTo(
                            _scrollController.position.maxScrollExtent -
                                extentAfter -
                                Global.screenHeight +
                                (Global.topHeight + 30 + 20));
                      }
                    }
                  });
                  //删除原来的记录,保存新的记录,查询
                  deleteOldUserIdAndChapter(novelChapterContent);
                  savaUserIdAndChapter(novelChapterContent);
                  checkNovelData(novelChapterContent);
                  mySetState(() {});
                  Future.delayed(const Duration(milliseconds: 100), () {
                    addDataCheckScreen();
                  });
                }
              } else {
                //免费章节
                double extentAfter = _scrollController.position.extentAfter;
                novelChapterContentList.insert(
                    0, novelChapterContent.chapterInfo!);
                startPage = startPage - 1;
                Future.delayed(const Duration(milliseconds: 100), () {
                  if (_scrollController.position.maxScrollExtent - extentAfter <
                      Global.screenHeight) {
                    if (_scrollController.hasClients) {
                      //+1防止跳到顶部又请求上一章了
                      _scrollController
                          .jumpTo(_scrollController.position.minScrollExtent+1);
                    }
                  } else {
                    if (_scrollController.hasClients) {
                      _scrollController.jumpTo(
                          _scrollController.position.maxScrollExtent -
                              extentAfter -
                              Global.screenHeight +
                              (Global.topHeight + 30 + 20));
                    }
                  }
                });
                //删除原来的记录,保存新的记录,查询
                deleteOldUserIdAndChapter(novelChapterContent);
                savaUserIdAndChapter(novelChapterContent);
                checkNovelData(novelChapterContent);
                mySetState(() {});
                Future.delayed(const Duration(milliseconds: 100), () {
                  addDataCheckScreen();
                });
              }
            } else {
              //往底部插入数据
              //不免费章节
              if (novelChapterContent.chapterInfo!.freeChapter == 2) {
                //判断是否已购买
                if (novelChapterContent.chapterInfo!.isBuy == 2) {
                  if (hasShowNovelFreeDialog) {
                  } else {
                    showModalBottomSheet(
                        shape: const RoundedRectangleBorder(
                            borderRadius: BorderRadius.only(
                                topLeft: Radius.circular(24),
                                topRight: Radius.circular(24))),
                        isScrollControlled: true,
                        enableDrag: false,
                        backgroundColor: CommonColors.getColorF5F8F5,
                        context: context,
                        builder: (context) =>
                            BuyNovelDialog(novelChapterContent)).then((value) {
                      if (value != null) {
                        if (value == true) {
                          if (checkListData(novelChapterContent) == false) {
                            novelChapterContentList
                                .add(novelChapterContent.chapterInfo!);
                            endPage = endPage + 1;
                          }
                          //如果列表大于屏幕,一进来就预留顶部位置
                          Future.delayed(const Duration(milliseconds: 100), () {
                            if (getListHeight() != null) {
                              if (getListHeight()! >= Global.screenHeight) {
                                if (_scrollController.hasClients) {
                                  _scrollController.jumpTo(_scrollController
                                          .position.minScrollExtent +
                                      1);
                                }
                              }
                            }
                          });
                          reGetNovelData(
                              widget.chapterInfo?.bookId ?? 1, endPage - 1);
                          //删除原来的记录,保存新的记录,查询
                          deleteOldUserIdAndChapter(novelChapterContent);
                          savaUserIdAndChapter(novelChapterContent);
                          checkNovelData(novelChapterContent);
                          mySetState(() {});
                          Future.delayed(const Duration(milliseconds: 100), () {
                            addDataCheckScreen();
                          });
                        }
                      } else {
                        //检查列表是否满屏
                        if (getData != null) {
                          if (getData = true) {
                            Future.delayed(const Duration(milliseconds: 100),
                                () {
                              addDataCheckScreen();
                            });
                            //章数直接传进来的就不要减了,因为没有加到
                          }
                        } else {
                          Future.delayed(const Duration(milliseconds: 100), () {
                            addDataCheckScreen();
                          });
                          // endPage = endPage - 1;
                        }
                      }
                    });
                  }
                } else {
                  //已经购买过该章节
                  novelChapterContentList.add(novelChapterContent.chapterInfo!);
                  endPage = endPage + 1;
                  if (getData != null) {
                    if (getData == true) {
                      //一进来就预留顶部位置
                      Future.delayed(const Duration(milliseconds: 100), () {
                        if (getListHeight() != null) {
                          if (getListHeight()! >= Global.screenHeight) {
                            if (_scrollController.hasClients) {
                              _scrollController.jumpTo(
                                  _scrollController.position.minScrollExtent +
                                      1);
                            }
                          }
                        }
                      });
                    }
                  }
                  //删除原来的记录,保存新的记录,查询
                  deleteOldUserIdAndChapter(novelChapterContent);
                  savaUserIdAndChapter(novelChapterContent);
                  checkNovelData(novelChapterContent);
                  mySetState(() {});
                  Future.delayed(const Duration(milliseconds: 100), () {
                    addDataCheckScreen();
                  });
                }
              } else {
                //免费章节
                novelChapterContentList.add(novelChapterContent.chapterInfo!);
                if (getData != null) {
                  if (getData == true) {
                    //一进来就预留顶部位置
                    Future.delayed(const Duration(milliseconds: 100), () {
                      if (getListHeight() != null) {
                        if (getListHeight()! >= Global.screenHeight) {
                          if (_scrollController.hasClients) {
                            _scrollController.jumpTo(
                                _scrollController.position.minScrollExtent + 1);
                          }
                        }
                      }
                    });
                  }
                }
                endPage = endPage + 1;
                //删除原来的记录,保存新的记录,查询
                deleteOldUserIdAndChapter(novelChapterContent);
                savaUserIdAndChapter(novelChapterContent);
                checkNovelData(novelChapterContent);
                mySetState(() {});
                Future.delayed(const Duration(milliseconds: 100), () {
                  addDataCheckScreen();
                });
              }
            }
          }
        }
      }
    }
  }

  //本地删除该书的旧章节
  deleteOldUserIdAndChapter(NovelChapterContent? novelChapterContent) {
    List<String> saveNovelDataList = [];
    if (SPHelper.getNovelDataList == null) {
      SPHelper.setNovelDataList([]);
      if (SPHelper.getNovelDataList != null) {
        saveNovelDataList = SPHelper.getNovelDataList;
        for (int i = 0; i < saveNovelDataList.length; i++) {
          SaveNovelData saveNovelData =
              SaveNovelData.fromJson(jsonDecode(saveNovelDataList[i]));
          if (saveNovelData.userId == Global.userId) {
            if (novelChapterContent != null) {
              if (novelChapterContent.chapterInfo != null) {
                if (saveNovelData.chapterInfo != null) {
                  if (novelChapterContent.chapterInfo!.bookId ==
                      saveNovelData.chapterInfo!.bookId) {
                    //保存有该书数据就删除
                    saveNovelDataList.removeAt(i);
                  }
                }
              }
            }
          }
        }
        //重新赋值
        SPHelper.setNovelDataList(saveNovelDataList);
      }
    } else {
      saveNovelDataList = SPHelper.getNovelDataList;
      for (int i = 0; i < saveNovelDataList.length; i++) {
        SaveNovelData saveNovelData =
            SaveNovelData.fromJson(jsonDecode(saveNovelDataList[i]));
        if (saveNovelData.userId == Global.userId) {
          if (novelChapterContent != null) {
            if (novelChapterContent.chapterInfo != null) {
              if (saveNovelData.chapterInfo != null) {
                if (novelChapterContent.chapterInfo!.bookId ==
                    saveNovelData.chapterInfo!.bookId) {
                  //保存有该书数据就删除
                  saveNovelDataList.removeAt(i);
                }
              }
            }
          }
        }
      }
      //重新赋值
      SPHelper.setNovelDataList(saveNovelDataList);
    }
  }

  //查询本地保存的小说记录,仅供自己使用
  checkNovelData(NovelChapterContent? novelChapterContent) {
    List<String> saveNovelDataList = [];
    if (SPHelper.getNovelDataList == null) {
      SPHelper.setNovelDataList([]);
      if (SPHelper.getNovelDataList != null) {
        saveNovelDataList = SPHelper.getNovelDataList;
        for (int i = 0; i < saveNovelDataList.length; i++) {
          SaveNovelData saveNovelData =
              SaveNovelData.fromJson(jsonDecode(saveNovelDataList[i]));
          if (saveNovelData.userId == Global.userId) {
            if (novelChapterContent != null) {
              if (novelChapterContent.chapterInfo != null) {
                if (saveNovelData.chapterInfo != null) {
                  if (novelChapterContent.chapterInfo!.bookId ==
                      saveNovelData.chapterInfo!.bookId) {}
                }
              }
            }
          }
        }
        //重新赋值
        SPHelper.setNovelDataList(saveNovelDataList);
      }
    } else {
      saveNovelDataList = SPHelper.getNovelDataList;
      for (int i = 0; i < saveNovelDataList.length; i++) {
        SaveNovelData saveNovelData =
            SaveNovelData.fromJson(jsonDecode(saveNovelDataList[i]));
        if (saveNovelData.userId == Global.userId) {
          if (novelChapterContent != null) {
            if (novelChapterContent.chapterInfo != null) {
              if (saveNovelData.chapterInfo != null) {
                if (novelChapterContent.chapterInfo!.bookId ==
                    saveNovelData.chapterInfo!.bookId) {}
              }
            }
          }
        }
      }
      //重新赋值
      SPHelper.setNovelDataList(saveNovelDataList);
    }
  }

  //本地添加该书的新章节记录
  savaUserIdAndChapter(NovelChapterContent? novelChapterContent) {
    if (novelChapterContent != null) {
      List<String> saveNovelDataList = [];
      //获取已经存好的数据
      if (SPHelper.getNovelDataList == null) {
        SPHelper.setNovelDataList([]);
        if (SPHelper.getNovelDataList != null) {
          saveNovelDataList = SPHelper.getNovelDataList;
          SaveNovelData saveNovelData = SaveNovelData(
              userId: Global.userId,
              chapterInfo: novelChapterContent.chapterInfo);
          saveNovelDataList.add(jsonEncode(saveNovelData.toJson()));
          SPHelper.setNovelDataList(saveNovelDataList);
        }
      } else {
        saveNovelDataList = SPHelper.getNovelDataList;
        SaveNovelData sayHiData = SaveNovelData(
            userId: Global.userId,
            chapterInfo: novelChapterContent.chapterInfo);
        saveNovelDataList.add(jsonEncode(sayHiData.toJson()));
        SPHelper.setNovelDataList(saveNovelDataList);
      }
    }
  }

  //点击屏幕上边和下边
  void _onTapDown(TapUpDetails details) async {
    /// 上边触摸
    startPosition = details.globalPosition;
    //频幕高度
    double layoutHeight = Global.screenHeight;
    if (startPosition.dy < (layoutHeight / 2)) {
      if (_scrollController.position.pixels -
              _scrollController.position.minScrollExtent >=
          Global.screenHeight) {
        if (_scrollController.hasClients) {
          _scrollController.animateTo(
            _scrollController.position.pixels -
                Global.screenHeight +
                (Global.topHeight + 30 + 20),
            duration: const Duration(milliseconds: 200),
            curve: Curves.linear,
          );
        }
      } else {
        if (_scrollController.hasClients) {
          _scrollController.animateTo(
            _scrollController.position.minScrollExtent,
            duration: const Duration(milliseconds: 200),
            curve: Curves.linear,
          );
        }
      }
    } else {
      /// 下边触摸
      if (_scrollController.position.maxScrollExtent -
              _scrollController.position.pixels >=
          Global.screenHeight) {
        if (_scrollController.hasClients) {
          _scrollController.animateTo(
            _scrollController.position.pixels +
                Global.screenHeight -
                (Global.topHeight + 30 + 20),
            duration: const Duration(milliseconds: 200),
            curve: Curves.linear,
          );
        }
      } else {
        if (_scrollController.hasClients) {
          _scrollController.animateTo(
            _scrollController.position.maxScrollExtent,
            duration: const Duration(milliseconds: 200),
            curve: Curves.linear,
          );
        }
      }
    }
  }

  //点击占位控件
  seatWidgetTap(TapUpDetails details){
    /// 上边触摸
    startPosition = details.globalPosition;
    //频幕高度
    double layoutHeight = Global.screenHeight;

    if (startPosition.dy < (layoutHeight / 2)) {
      if (_scrollController.position.pixels -
          _scrollController.position.minScrollExtent >=
          Global.screenHeight) {
        if (_scrollController.hasClients) {
          _scrollController.animateTo(
            _scrollController.position.pixels -
                Global.screenHeight +
                (Global.topHeight + 30 + 20),
            duration: const Duration(milliseconds: 200),
            curve: Curves.linear,
          );
        }
      } else {
        if (_scrollController.hasClients) {
          _scrollController.animateTo(
            _scrollController.position.minScrollExtent,
            duration: const Duration(milliseconds: 200),
            curve: Curves.linear,
          );
        }
      }
    } else {
      /// 下边触摸
      if (_scrollController.position.maxScrollExtent -
          _scrollController.position.pixels >=
          Global.screenHeight) {
        if (_scrollController.hasClients) {
          _scrollController.animateTo(
            _scrollController.position.pixels +
                Global.screenHeight -
                (Global.topHeight + 30 + 20),
            duration: const Duration(milliseconds: 200),
            curve: Curves.linear,
          );
        }
      } else {
        if (_scrollController.hasClients) {
          _scrollController.animateTo(
            _scrollController.position.maxScrollExtent,
            duration: const Duration(milliseconds: 200),
            curve: Curves.linear,
          );
        }
      }
    }
  }

  @override
  void dispose() {
    _scrollController.dispose();
    if (novelDialogHasShowEvent != null) {
      novelDialogHasShowEvent!.cancel();
    }
    super.dispose();
  }

  //没有满屏,滑动列表的时候
  //用了一次就失效了,可能是因为控制权被SingleChildScrollView的控制器抢走了
  _onVerticalDragStart(DragUpdateDetails details) {
    final containerHeight = _globalKey.currentContext?.size?.height;
    final listHeight = listGlobalKey.currentContext
        ?.findRenderObject()
        ?.semanticBounds
        .size
        .height;

    if (containerHeight != null) {
      if (listHeight != null) {
        if (containerHeight + listHeight < Global.screenHeight) {
          seatHeight = Global.screenHeight - containerHeight - listHeight + 10;
          showSeat = true;
          mySetState(() {});
        }
      }
    }
  }

  ///检查内容高度是否大于屏幕高度,不大于就填充一个控件,保证列表可以滑动
  addDataCheckScreen() {
    //顶部高度
    final containerHeight = _globalKey.currentContext?.size?.height;
    //实际列表高度
    final listHeight = listGlobalKey.currentContext
        ?.findRenderObject()
        ?.semanticBounds
        .size
        .height;

    if (containerHeight != null) {
      if (listHeight != null) {
        //如果总的列表高度-前一个填充高度还是小于屏幕高度减顶部高度,重新计算填充的高度
        if (listHeight - seatHeight <= Global.screenHeight - containerHeight) {
          //全屏减顶部等于列表高度,如果第一次进来没满屏幕,就填充
          if (listHeight <= Global.screenHeight - containerHeight) {
            seatHeight =
                Global.screenHeight - containerHeight - listHeight + 10;
          } else {
            //加上占位已经满屏幕了,但数据没满屏幕,重新计算占位高度。或者数据本身已经满屏幕了这个就可以隐藏占位符
            if (listHeight - seatHeight <=
                Global.screenHeight - containerHeight) {
              //实际列表高度小于屏幕高度
              seatHeight = Global.screenHeight -
                  containerHeight -
                  (listHeight - seatHeight) +
                  10;
            } else {
              //实际列表高度大于屏幕高度
              showSeat = false;
              mySetState(() {});
            }
          }
          showSeat = true;
          mySetState(() {});
        } else {
          //隐藏占位
          showSeat = false;
          mySetState(() {});
        }
        if (showSeat == true) {
          //数据还没满屏,要让顶部有距离
          if (_scrollController.hasClients) {
            //添加数据后,当前位置等于0,即在顶部的时候才预留顶部位置
            if(_scrollController.position.pixels==_scrollController.position.minScrollExtent){
              _scrollController
                  .jumpTo(_scrollController.position.minScrollExtent + 1);
            }
          }
        }
      }
    }
  }

  //返回列表高度
  double? getListHeight() {
    double? listH;
    final listHeight = listGlobalKey.currentContext
        ?.findRenderObject()
        ?.semanticBounds
        .size
        .height;
    if (listHeight != null) {
      listH = listHeight;
    }
    return listH;
  }

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Stack(
        alignment: Alignment.bottomCenter,
        children: [
          Container(
              decoration: const BoxDecoration(
                  image: DecorationImage(
                      image: AssetImage('assets/images/bg_novel_read.png'),
                      fit: BoxFit.fill // 完全填充
                      )),
              padding: EdgeInsets.only(bottom: 20.r),
              child: GestureDetector(
                // onVerticalDragUpdate: _onVerticalDragStart,
                child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      addHeadView(),
                      Expanded(
                          child: SingleChildScrollView(
                              controller: _scrollController,
                              scrollDirection: Axis.vertical,
                              child: Column(
                                  key: listGlobalKey,
                                  mainAxisAlignment: MainAxisAlignment.start,
                                  children: [
                                    MediaQuery.removePadding(
                                      removeTop: true,
                                      context: context,
                                      child: ListView.builder(
                                        itemCount:
                                            novelChapterContentList.length,
                                        physics:
                                            const NeverScrollableScrollPhysics(),
                                        shrinkWrap: true,
                                        itemBuilder:
                                            (BuildContext context, int index) {
                                          return GestureDetector(
                                            onTapUp: _onTapDown,
                                            child: Container(
                                              margin: EdgeInsets.only(
                                                  left: 16.r, right: 16.r),
                                              padding:
                                                  EdgeInsets.only(bottom: 20.r),
                                              child: Column(
                                                crossAxisAlignment:
                                                    CrossAxisAlignment.start,
                                                mainAxisAlignment:
                                                    MainAxisAlignment.start,
                                                children: [
                                                  //下拉加载下一页,列表拼接,显示对象里的文本字段
                                                  Container(
                                                    alignment:
                                                        Alignment.centerLeft,
                                                    padding: EdgeInsets.only(
                                                        bottom: 15.0.r,
                                                        top: 30.r),
                                                    child: Text(
                                                      novelChapterContentList[
                                                                  index]
                                                              .title ??
                                                          '',
                                                      style: TextStyle(
                                                          color: const Color(
                                                              0xFF222222),
                                                          fontSize: 24.sp),
                                                    ),
                                                  ),
                                                  Text(
                                                      novelChapterContentList[
                                                                  index]
                                                              .content ??
                                                          '',
                                                      style: TextStyle(
                                                          color: const Color(
                                                              0xFF222222),
                                                          fontSize: 20.sp,
                                                          height: 2.2,
                                                          letterSpacing: 1.5)),
                                                ],
                                              ),
                                            ),
                                          );
                                        },
                                      ),
                                    ),
                                    if (showSeat)
                                      GestureDetector(
                                        onTapUp: seatWidgetTap,
                                        child: Container(
                                          height: seatHeight,
                                          color: Colors.transparent,
                                        ),
                                      )
                                  ]))),
                    ]),
              )),
          showLoading
              ? Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Container(
                      padding: EdgeInsets.only(bottom: 3.r),
                      alignment: Alignment.center,
                      width: 16.r,
                      height: 16.r,
                      child: const LoadingIndicator(
                          indicatorType: Indicator.circleStrokeSpin,

                          /// Required, The loading type of the widget
                          colors: [Color(0xFFFF4E68)],

                          /// Optional, The color collections
                          strokeWidth: 2,

                          /// Optional, The stroke of the line, only applicable to widget which contains line
                          backgroundColor: Colors.transparent,

                          /// Optional, Background of the widget
                          pathBackgroundColor: Color(0xCCFFFFFF)

                          /// Optional, the stroke backgroundColor
                          ),
                    ),
                  ],
                )
              : Container()
        ],
      ),
    );
  }

  Widget addHeadView() {
    return Container(
        key: _globalKey,
        padding:
            EdgeInsets.only(top: Global.topHeight + 10, left: 12.r, right: 5.r),
        child: Row(children: [
          GestureDetector(
            onTap: () {
              Navigator.pop(context);
            },
            child: const Image(
              image: AssetImage('assets/images/icon_back@2x.png'),
              width: 24,
              height: 25,
              color: Colors.black,
            ),
          ),
          LimitedBox(
            maxWidth: Global.screenWidth - 50,
            child: Text(
              "${widget.novelName}",
              style: const TextStyle(color: Color(0xFF222222), fontSize: 16),
              maxLines: 1,
              overflow: TextOverflow.ellipsis,
            ),
          )
        ]));
  }
}

用自定义列表写的小说代码,上下两个列表,顶部为分割线,上无穷,下无穷,就不会跳跃了

import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:loading_indicator/loading_indicator.dart';
import 'package:social_im/pages/read_book/buy_novel_dialog.dart';
import 'package:social_im/utils/printUtil.dart';
import '../../common/Global.dart';
import '../../common/colors.dart';
import '../../common/globalEventBus.dart';
import '../../config/shared_preferences_helper.dart';
import '../../http/api.dart';
import '../../http/net_callback.dart';
import '../../http/rxhttp.dart';
import '../../http/utils/NetUtils.dart';
import '../../http/utils/response.dart';
import 'novelModel/novel_chapter_content.dart';
import 'novelModel/novel_details_model.dart';
import 'novelModel/save_novel_data.dart';

//小说阅读页
class ReadPageNew extends StatefulWidget {
  ChapterInfo? chapterInfo;
  String? novelName;

  ReadPageNew(this.chapterInfo, this.novelName, {Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() => ReadPageNewState();
}

class ReadPageNewState extends State<ReadPageNew> {
  //列表控制器
  final ScrollController _scrollController = ScrollController();

  //还有更多数据
  bool hasMore = true;

  //上划的章数
  int startPage = 0;

  //最开始的章数
  int firstPage = 0;

  //下滑的章数
  int endPage = 0;

  //点击的位置
  late Offset startPosition;

  //顶部布局的高度,59
  final GlobalKey _globalKey = GlobalKey();

  //底部数据列表的高度
  GlobalKey listGlobalDownKey = GlobalKey();

  //顶部数据列表的高度
  GlobalKey listGlobalUpKey = GlobalKey();

  //设置列表中心位置
  var centerKey = GlobalKey();

  //数据列表的高度小于满屏高度减顶部高度时,填充一个占位高度,确保可以滑动
  double seatHeight = 0.0;

  //是否显示占位符
  bool showSeat = false;

  //小说底部列表内容
  List<ChapterInfo> novelContentDownList = [];

  //小说顶部列表内容
  List<ChapterInfo> novelContentUpList = [];

  //扣费弹窗已弹出,不可以再弹出来了
  StreamSubscription<NovelDialogHasShow>? novelDialogHasShowEvent;

  //已显示小说扣费弹窗
  bool hasShowNovelFreeDialog = false;

  //是否显示底部loading
  bool showLoading = false;

  //是否正在进行网络请求
  bool hasHttpRes = false;

  ///一秒内只监听列表滑动一次划到低部,防止多次请求
  bool scrollListener = false;

  //头部距离列表的距离
  double paddingSize = 20.0;

  @override
  void initState() {
    //扣费弹窗已弹出来,不可以再弹了
    novelDialogHasShowEvent = EventBusUtil.listen((event) {
      if (event.hasShow) {
        hasShowNovelFreeDialog = true;
      } else {
        hasShowNovelFreeDialog = false;
      }
    });
    //显示loading
    showLoading = true;
    //获取小说数据
    getNovelData(widget.chapterInfo?.bookId ?? 1,
        widget.chapterInfo?.chapter ?? 1, false,
        initGetData: true);
    //标记最开始的章节
    startPage = widget.chapterInfo?.chapter ?? 1;
    if (startPage >= 2) {
      //上一章的章节数等于传进来的章节数减一
      startPage = startPage - 1;
    }
    //标记最末尾的章节
    endPage = widget.chapterInfo?.chapter ?? 1;

    // 监听滚动事件:注意:请求数据的时候不可能让页数+1了
    //拉到最底部,请求下一章数据
    _scrollController.addListener(() {
      //防止一次监听到两次滑到最底部
      if (scrollListener == false) {
        if (_scrollController.position.pixels ==
            _scrollController.position.maxScrollExtent) {
          //已经拉到一次底部了
          scrollListener = true;
          //达到最大滚动位置
          if (hasMore) {
            mySetState(() {
              //显示loading
              showLoading = true;
              //不是往顶部添加数据
              bool start = false;
              //要在添加数据之前跳转,不然就会出现,添加数据完成后直接跳到末尾了
              if (_scrollController.hasClients) {
                _scrollController
                    .jumpTo(_scrollController.position.maxScrollExtent - 1);
              }
              //请求数据
              getNovelData(widget.chapterInfo?.bookId ?? 1, endPage, start);
            });
          }

          //延时一秒才可以再监听滑到底部
          Future.delayed(const Duration(milliseconds: 1000), () {
            scrollListener = false;
          });
        }
      } else {
        if (_scrollController.position.pixels ==
            _scrollController.position.maxScrollExtent) {
          if (_scrollController.hasClients) {
            _scrollController
                .jumpTo(_scrollController.position.maxScrollExtent - 1);
          }
        }
      }

      //拉到最顶部,请求上一章
      if (_scrollController.position.pixels ==
          _scrollController.position.minScrollExtent) {
        //这个监听列表的高度最大只能是该屏幕列表占的最大实际高度,20是顶部padding,顶部头部布局,剩下的就是列表高度了
        if (getDoubleListHeight() >=
            Global.screenHeight - paddingSize - getHeadHeight()) {
          if (_scrollController.hasClients) {
            _scrollController
                .jumpTo(_scrollController.position.minScrollExtent + 1);
          }
        } else if (getDoubleListHeight() + seatHeight >=
            Global.screenHeight - paddingSize - getHeadHeight()) {
          //(一进来的数据没满屏),列表的高度+填充高度大于满屏就网上挪一下
          if (showSeat == true) {
            if (_scrollController.hasClients) {
              _scrollController
                  .jumpTo(_scrollController.position.minScrollExtent + 1);
            }
          }
        }

        //往顶部添加数据
        bool start = true;
        //大于等于第一章才请求
        if (hasMore) {
          mySetState(() {
            if (startPage >= 1) {
              getNovelData(widget.chapterInfo?.bookId ?? 1, startPage, start);
            }
          });
        }
      }
    });

    super.initState();
  }

  mySetState(callBack) {
    if (mounted) {
      setState(() {
        callBack();
      });
    }
  }

  //获取小说具体内容
  getNovelData(int bookId, int chapter, bool isStart, {bool? initGetData}) {
    RxHttp<Response>()
      ..init()
      ..setBaseUrl(Api.BUSINESS_BASE_API)
      ..setPath(Api.API_BOOK_CONTENT)
      ..setCacheMode(CacheMode.FIRST_CACHE_THEN_REQUEST)
      ..setJsonTransFrom((p0) => Response.fromJson(json.decoder.convert(p0)))
      ..setParams({
        "book_id": bookId,
        "chapter": chapter,
      })
      ..call(
          NetCallback(onNetFinish: (response) {
            //加延时防止滑动列表短时间重复请求
            if (response.code == 0 || response.code == 200) {
              //为false就处理数据
              log('小说数据11112 ${json.encode(response.data)}');
              NovelChapterContent? novelChapterContent =
                  NovelChapterContent.fromJson(response.data);
              handleNovel(novelChapterContent, isStart, initGetData);
              if (mounted) {
                setState(() {});
              }
            }
          }, onCacheFinish: (response) {
            if (response.code == 0 || response.code == 200) {
              NovelChapterContent? novelChapterContent =
                  NovelChapterContent.fromJson(response.data);
              log('小说数据1111 ${json.encode(response.data)}');
              //如果该章节需要扣费,且还没有购买,就不执行
              if (novelChapterContent.chapterInfo != null) {
                if (novelChapterContent.chapterInfo!.freeChapter != null) {
                  //免费的就让缓存执行
                  if (novelChapterContent.chapterInfo!.freeChapter == 1) {
                    handleNovel(novelChapterContent, isStart, initGetData);
                  } else {
                    //收费但是已经购买的可以让缓存执行
                    if (novelChapterContent.chapterInfo!.isBuy != null) {
                      //已经购买
                      if (novelChapterContent.chapterInfo!.isBuy == 1) {
                        handleNovel(novelChapterContent, isStart, initGetData);
                      }
                    }
                  }
                }
              }
              if (mounted) {
                setState(() {});
              }
            }
          }, onNetError: (errorCode, error) {
            showLoading = false;
            mySetState(() {});
            // showToast('$error ($errorCode)');
          }),
          server: Servers.businessServer);
  }

  //点进去需要扣费,缓存需要扣费,购买过小说后再请求一次,刷新缓存,免得进来还是先拿缓存还要扣费
  reGetNovelData(int bookId, int chapter) {
    if (chapter <= 0) {
      return;
    }
    RxHttp<Response>()
      ..init()
      ..setBaseUrl(Api.BUSINESS_BASE_API)
      ..setPath(Api.API_BOOK_CONTENT)
      ..setCacheMode(CacheMode.REQUEST_FAILED_READ_CACHE)
      ..setJsonTransFrom((p0) => Response.fromJson(json.decoder.convert(p0)))
      ..setParams({
        "book_id": bookId,
        "chapter": chapter,
      })
      ..call(
          NetCallback(
              onNetFinish: (response) {},
              onCacheFinish: (response) {},
              onNetError: (errorCode, error) {}),
          server: Servers.businessServer);
  }

  //添加数据时,查找当前底部列表是否有重复数据
  checkDownListData(NovelChapterContent? novelChapterContent) {
    bool isHasData = false;
    if (novelChapterContent != null) {
      if (novelChapterContent.chapterInfo != null) {
        for (int i = 0; i < novelContentDownList.length; i++) {
          if (novelContentDownList[i].bookId ==
              novelChapterContent.chapterInfo!.bookId) {
            if (novelContentDownList[i].chapter ==
                novelChapterContent.chapterInfo!.chapter) {
              isHasData = true;
            }
          }
        }
      }
    }
    return isHasData;
  }

  //添加数据时,查找当前顶部列表是否有重复数据
  checkUpListData(NovelChapterContent? novelChapterContent) {
    bool isHasData = false;
    if (novelChapterContent != null) {
      if (novelChapterContent.chapterInfo != null) {
        for (int i = 0; i < novelContentUpList.length; i++) {
          if (novelContentUpList[i].bookId ==
              novelChapterContent.chapterInfo!.bookId) {
            if (novelContentUpList[i].chapter ==
                novelChapterContent.chapterInfo!.chapter) {
              isHasData = true;
            }
          }
        }
      }
    }
    return isHasData;
  }

  //处理小说扣费
  //添加数据时检查列表是否够满屏,没满屏的话显示控件
  handleNovel(
      NovelChapterContent? novelChapterContent, bool isStart, bool? initData) {
    showLoading = false;
    if (novelChapterContent != null) {
      if (novelChapterContent.chapterInfo != null) {
        if (isStart) {
          //顶部列表去重
          if (!novelContentUpList.contains(novelChapterContent.chapterInfo)) {
            //顶部列表遍历去重
            if (checkUpListData(novelChapterContent) == false) {
              //底部列表contains去重
              if (!novelContentDownList
                  .contains(novelChapterContent.chapterInfo)) {
                //底部列表遍历去重,其实应该要删掉旧的数据(缓存),添加新的数据(网络)
                if (checkDownListData(novelChapterContent) == false) {
                  //往顶部插入数据
                  //不免费章节
                  if (novelChapterContent.chapterInfo!.freeChapter == 2) {
                    //判断是否已购买
                    if (novelChapterContent.chapterInfo!.isBuy == 2) {
                      //已经弹出扣费弹窗了,就不再弹
                      if (hasShowNovelFreeDialog) {
                      } else {
                        showModalBottomSheet(
                                shape: const RoundedRectangleBorder(
                                    borderRadius: BorderRadius.only(
                                        topLeft: Radius.circular(24),
                                        topRight: Radius.circular(24))),
                                isScrollControlled: true,
                                enableDrag: false,
                                backgroundColor: CommonColors.getColorF5F8F5,
                                context: context,
                                builder: (context) =>
                                    BuyNovelDialog(novelChapterContent))
                            .then((value) {
                          if (value != null) {
                            if (value == true) {
                              //购买了本书
                              //顶部列表去重
                              if (checkUpListData(novelChapterContent) ==
                                  false) {
                                //底部列表去重
                                if (checkDownListData(novelChapterContent) ==
                                    false) {
                                  //底部列表为空的时候优先插入底部列表,不然就是空白一片了
                                  if(novelContentDownList.isEmpty){
                                    novelContentDownList.add(novelChapterContent.chapterInfo!);
                                  }else{
                                    //底部列表的高度不够屏幕高度时,优先插入数据在底部列表
                                    if(getDownListHeight()<Global.screenHeight - paddingSize - getHeadHeight()){
                                      novelContentDownList.insert(0,novelChapterContent.chapterInfo!);
                                      PrintUtil.prints('优先插入数据到底部列表');
                                    }else{
                                      novelContentUpList.insert(
                                          0, novelChapterContent.chapterInfo!);
                                    }
                                  }
                                  novelContentDownList.sort((a, b) =>
                                      a.chapter!.compareTo(b.chapter!));
                                  novelContentUpList.sort((a, b) =>
                                      a.chapter!.compareTo(b.chapter!));
                                  startPage = startPage - 1;
                                }
                              }
                              //重新请求一下数据,刷新缓存数据
                              reGetNovelData(widget.chapterInfo?.bookId ?? 1,
                                  startPage + 1);
                              //删除原来的记录,保存新的记录,查询
                              deleteOldUserIdAndChapter(novelChapterContent);
                              savaUserIdAndChapter(novelChapterContent);
                              checkNovelData(novelChapterContent);
                              mySetState(() {});
                              Future.delayed(const Duration(milliseconds: 100),
                                  () {
                                addSeatWidget();
                              });
                            }
                          } else {
                            //没购买到章节,不做处理
                          }
                        });
                      }
                    } else {
                      //已购买过章节
                      //底部列表为空的时候优先插入底部列表,不然就是空白一片了
                      if(novelContentDownList.isEmpty){
                        novelContentDownList.add(novelChapterContent.chapterInfo!);
                      }else{
                        //底部列表的高度不够屏幕高度时,优先插入数据在底部列表
                        if(getDownListHeight()<Global.screenHeight - paddingSize - getHeadHeight()){
                          novelContentDownList.insert(0,novelChapterContent.chapterInfo!);
                          PrintUtil.prints('优先插入数据到底部列表');
                        }else{
                          novelContentUpList.insert(
                              0, novelChapterContent.chapterInfo!);
                        }
                      }
                      novelContentDownList
                          .sort((a, b) => a.chapter!.compareTo(b.chapter!));
                      novelContentUpList
                          .sort((a, b) => a.chapter!.compareTo(b.chapter!));
                      startPage = startPage - 1;
                      //删除原来的记录,保存新的记录,查询
                      deleteOldUserIdAndChapter(novelChapterContent);
                      savaUserIdAndChapter(novelChapterContent);
                      checkNovelData(novelChapterContent);
                      mySetState(() {});
                      Future.delayed(const Duration(milliseconds: 100), () {
                        addSeatWidget();
                      });
                    }
                  } else {
                    //免费章节
                    //底部列表为空的时候优先插入底部列表,不然就是空白一片了
                    if(novelContentDownList.isEmpty){
                      novelContentDownList.add(novelChapterContent.chapterInfo!);
                    }else{
                      //底部列表的高度不够屏幕高度时,优先插入数据在底部列表
                      if(getDownListHeight()<Global.screenHeight - paddingSize - getHeadHeight()){
                        novelContentDownList.insert(0,novelChapterContent.chapterInfo!);
                        PrintUtil.prints('优先插入数据到底部列表');
                      }else{
                        novelContentUpList.insert(
                            0, novelChapterContent.chapterInfo!);
                      }
                    }
                    novelContentUpList
                        .sort((a, b) => a.chapter!.compareTo(b.chapter!));
                    novelContentDownList
                        .sort((a, b) => a.chapter!.compareTo(b.chapter!));
                    startPage = startPage - 1;
                    //删除原来的记录,保存新的记录,查询
                    deleteOldUserIdAndChapter(novelChapterContent);
                    savaUserIdAndChapter(novelChapterContent);
                    checkNovelData(novelChapterContent);
                    mySetState(() {});
                    Future.delayed(const Duration(milliseconds: 100), () {
                      addSeatWidget();
                    });
                  }
                }
              }
            }
          }
        } else {
          //contains去重
          if (!novelContentDownList.contains(novelChapterContent.chapterInfo)) {
            //遍历去重,其实应该要删掉旧的数据(缓存),添加新的数据(网络)
            if (checkDownListData(novelChapterContent) == false) {
              if (!novelContentUpList
                  .contains(novelChapterContent.chapterInfo)) {
                if (checkUpListData(novelChapterContent) == false) {
                  //往底部插入数据
                  //不免费章节
                  if (novelChapterContent.chapterInfo!.freeChapter == 2) {
                    //判断是否已购买
                    if (novelChapterContent.chapterInfo!.isBuy == 2) {
                      if (hasShowNovelFreeDialog) {
                      } else {
                        showModalBottomSheet(
                                shape: const RoundedRectangleBorder(
                                    borderRadius: BorderRadius.only(
                                        topLeft: Radius.circular(24),
                                        topRight: Radius.circular(24))),
                                isScrollControlled: true,
                                enableDrag: false,
                                backgroundColor: CommonColors.getColorF5F8F5,
                                context: context,
                                builder: (context) =>
                                    BuyNovelDialog(novelChapterContent))
                            .then((value) {
                          if (value != null) {
                            if (value == true) {
                              //已购买小说
                              if (checkDownListData(novelChapterContent) ==
                                  false) {
                                if (checkUpListData(novelChapterContent) ==
                                    false) {
                                  novelContentDownList
                                      .add(novelChapterContent.chapterInfo!);
                                  novelContentDownList.sort((a, b) =>
                                      a.chapter!.compareTo(b.chapter!));
                                  endPage = endPage + 1;
                                }
                              }
                              //如果列表大于屏幕,一进来就预留顶部位置
                              Future.delayed(const Duration(milliseconds: 100),
                                  () {
                                if (getDoubleListHeight() >=
                                    Global.screenHeight -
                                        paddingSize -
                                        getHeadHeight()) {
                                  //添加数据后本身在顶部才跳转一个单位预留位置
                                  if (_scrollController.position.pixels ==
                                      _scrollController
                                          .position.minScrollExtent) {
                                    if (_scrollController.hasClients) {
                                      _scrollController.jumpTo(_scrollController
                                              .position.minScrollExtent +
                                          1);
                                    }
                                  }
                                }
                              });
                              //重新请求一下数据,刷新缓存
                              reGetNovelData(
                                  widget.chapterInfo?.bookId ?? 1, endPage - 1);
                              //删除原来的记录,保存新的记录,查询
                              deleteOldUserIdAndChapter(novelChapterContent);
                              savaUserIdAndChapter(novelChapterContent);
                              checkNovelData(novelChapterContent);
                              mySetState(() {});
                              Future.delayed(const Duration(milliseconds: 100),
                                  () {
                                addSeatWidget();
                              });
                            }
                          } else {
                            //没购买到小说
                            //检查列表是否满屏
                            if (initData != null) {
                              if (initData = true) {
                                Future.delayed(
                                    const Duration(milliseconds: 100), () {
                                  addSeatWidget();
                                });
                              }
                            } else {
                              Future.delayed(const Duration(milliseconds: 100),
                                  () {
                                addSeatWidget();
                              });
                            }
                          }
                        });
                      }
                    } else {
                      //已经购买过该章节
                      novelContentDownList
                          .add(novelChapterContent.chapterInfo!);
                      novelContentDownList
                          .sort((a, b) => a.chapter!.compareTo(b.chapter!));
                      endPage = endPage + 1;
                      if (initData != null) {
                        if (initData == true) {
                          //一进来就预留顶部位置
                          Future.delayed(const Duration(milliseconds: 100), () {
                            if (getDoubleListHeight() >=
                                Global.screenHeight -
                                    paddingSize -
                                    getHeadHeight()) {
                              //添加数据后本身在顶部才跳转一个单位预留位置
                              if (_scrollController.position.pixels ==
                                  _scrollController.position.minScrollExtent) {
                                if (_scrollController.hasClients) {
                                  _scrollController.jumpTo(_scrollController
                                          .position.minScrollExtent +
                                      1);
                                }
                              }
                            }
                          });
                        }
                      }
                      //删除原来的记录,保存新的记录,查询
                      deleteOldUserIdAndChapter(novelChapterContent);
                      savaUserIdAndChapter(novelChapterContent);
                      checkNovelData(novelChapterContent);
                      mySetState(() {});
                      Future.delayed(const Duration(milliseconds: 100), () {
                        addSeatWidget();
                      });
                    }
                  } else {
                    //免费章节
                    novelContentDownList.add(novelChapterContent.chapterInfo!);
                    novelContentDownList
                        .sort((a, b) => a.chapter!.compareTo(b.chapter!));
                    if (initData != null) {
                      if (initData == true) {
                        //一进来就预留顶部位置
                        Future.delayed(const Duration(milliseconds: 100), () {
                          if (getDoubleListHeight() >=
                              Global.screenHeight -
                                  paddingSize -
                                  getHeadHeight()) {
                            //添加数据后本身在顶部才跳转一个单位预留位置
                            if (_scrollController.position.pixels ==
                                _scrollController.position.minScrollExtent) {
                              if (_scrollController.hasClients) {
                                _scrollController.jumpTo(
                                    _scrollController.position.minScrollExtent +
                                        1);
                              }
                            }
                          }
                        });
                      }
                    }
                    endPage = endPage + 1;
                    //删除原来的记录,保存新的记录,查询
                    deleteOldUserIdAndChapter(novelChapterContent);
                    savaUserIdAndChapter(novelChapterContent);
                    checkNovelData(novelChapterContent);
                    mySetState(() {});
                    Future.delayed(const Duration(milliseconds: 100), () {
                      addSeatWidget();
                    });
                  }
                }
              }
            }
          }
        }
      }
    }
  }

  //本地删除该书的旧章节
  deleteOldUserIdAndChapter(NovelChapterContent? novelChapterContent) {
    List<String> saveNovelDataList = [];
    if (SPHelper.getNovelDataList == null) {
      SPHelper.setNovelDataList([]);
      if (SPHelper.getNovelDataList != null) {
        saveNovelDataList = SPHelper.getNovelDataList;
        for (int i = 0; i < saveNovelDataList.length; i++) {
          SaveNovelData saveNovelData =
              SaveNovelData.fromJson(jsonDecode(saveNovelDataList[i]));
          if (saveNovelData.userId == Global.userId) {
            if (novelChapterContent != null) {
              if (novelChapterContent.chapterInfo != null) {
                if (saveNovelData.chapterInfo != null) {
                  if (novelChapterContent.chapterInfo!.bookId ==
                      saveNovelData.chapterInfo!.bookId) {
                    //保存有该书数据就删除
                    saveNovelDataList.removeAt(i);
                  }
                }
              }
            }
          }
        }
        //重新赋值
        SPHelper.setNovelDataList(saveNovelDataList);
      }
    } else {
      saveNovelDataList = SPHelper.getNovelDataList;
      for (int i = 0; i < saveNovelDataList.length; i++) {
        SaveNovelData saveNovelData =
            SaveNovelData.fromJson(jsonDecode(saveNovelDataList[i]));
        if (saveNovelData.userId == Global.userId) {
          if (novelChapterContent != null) {
            if (novelChapterContent.chapterInfo != null) {
              if (saveNovelData.chapterInfo != null) {
                if (novelChapterContent.chapterInfo!.bookId ==
                    saveNovelData.chapterInfo!.bookId) {
                  //保存有该书数据就删除
                  saveNovelDataList.removeAt(i);
                }
              }
            }
          }
        }
      }
      //重新赋值
      SPHelper.setNovelDataList(saveNovelDataList);
    }
  }

  //查询本地保存的小说记录,仅供自己使用
  checkNovelData(NovelChapterContent? novelChapterContent) {
    List<String> saveNovelDataList = [];
    if (SPHelper.getNovelDataList == null) {
      SPHelper.setNovelDataList([]);
      if (SPHelper.getNovelDataList != null) {
        saveNovelDataList = SPHelper.getNovelDataList;
        for (int i = 0; i < saveNovelDataList.length; i++) {
          SaveNovelData saveNovelData =
              SaveNovelData.fromJson(jsonDecode(saveNovelDataList[i]));
          if (saveNovelData.userId == Global.userId) {
            if (novelChapterContent != null) {
              if (novelChapterContent.chapterInfo != null) {
                if (saveNovelData.chapterInfo != null) {
                  if (novelChapterContent.chapterInfo!.bookId ==
                      saveNovelData.chapterInfo!.bookId) {}
                }
              }
            }
          }
        }
        //重新赋值
        SPHelper.setNovelDataList(saveNovelDataList);
      }
    } else {
      saveNovelDataList = SPHelper.getNovelDataList;
      for (int i = 0; i < saveNovelDataList.length; i++) {
        SaveNovelData saveNovelData =
            SaveNovelData.fromJson(jsonDecode(saveNovelDataList[i]));
        if (saveNovelData.userId == Global.userId) {
          if (novelChapterContent != null) {
            if (novelChapterContent.chapterInfo != null) {
              if (saveNovelData.chapterInfo != null) {
                if (novelChapterContent.chapterInfo!.bookId ==
                    saveNovelData.chapterInfo!.bookId) {}
              }
            }
          }
        }
      }
      //重新赋值
      SPHelper.setNovelDataList(saveNovelDataList);
    }
  }

  //本地添加该书的新章节记录
  savaUserIdAndChapter(NovelChapterContent? novelChapterContent) {
    if (novelChapterContent != null) {
      List<String> saveNovelDataList = [];
      //获取已经存好的数据
      if (SPHelper.getNovelDataList == null) {
        SPHelper.setNovelDataList([]);
        if (SPHelper.getNovelDataList != null) {
          saveNovelDataList = SPHelper.getNovelDataList;
          SaveNovelData saveNovelData = SaveNovelData(
              userId: Global.userId,
              chapterInfo: novelChapterContent.chapterInfo);
          saveNovelDataList.add(jsonEncode(saveNovelData.toJson()));
          SPHelper.setNovelDataList(saveNovelDataList);
        }
      } else {
        saveNovelDataList = SPHelper.getNovelDataList;
        SaveNovelData sayHiData = SaveNovelData(
            userId: Global.userId,
            chapterInfo: novelChapterContent.chapterInfo);
        saveNovelDataList.add(jsonEncode(sayHiData.toJson()));
        SPHelper.setNovelDataList(saveNovelDataList);
      }
    }
  }

  //点击屏幕上边和下边
  void _onTapDown(TapUpDetails details) async {
    /// 上边触摸
    startPosition = details.globalPosition;
    //频幕高度
    double layoutHeight = Global.screenHeight;
    if (startPosition.dy < (layoutHeight / 2)) {
      if (_scrollController.position.pixels -
              _scrollController.position.minScrollExtent >=
          Global.screenHeight) {
        if (_scrollController.hasClients) {
          _scrollController.animateTo(
            _scrollController.position.pixels -
                Global.screenHeight +
                (Global.topHeight + 30 + 20),
            duration: const Duration(milliseconds: 200),
            curve: Curves.linear,
          );
        }
      } else {
        if (_scrollController.hasClients) {
          _scrollController.animateTo(
            _scrollController.position.minScrollExtent,
            duration: const Duration(milliseconds: 200),
            curve: Curves.linear,
          );
        }
      }
    } else {
      /// 下边触摸
      if (_scrollController.position.maxScrollExtent -
              _scrollController.position.pixels >=
          Global.screenHeight) {
        if (_scrollController.hasClients) {
          _scrollController.animateTo(
            _scrollController.position.pixels +
                Global.screenHeight -
                (Global.topHeight + 30 + 20),
            duration: const Duration(milliseconds: 200),
            curve: Curves.linear,
          );
        }
      } else {
        if (_scrollController.hasClients) {
          _scrollController.animateTo(
            _scrollController.position.maxScrollExtent,
            duration: const Duration(milliseconds: 200),
            curve: Curves.linear,
          );
        }
      }
    }
  }

  //点击占位控件
  seatWidgetTap(TapUpDetails details) {
    /// 上边触摸
    startPosition = details.globalPosition;
    //频幕高度
    double layoutHeight = Global.screenHeight;

    if (startPosition.dy < (layoutHeight / 2)) {
      if (_scrollController.position.pixels -
              _scrollController.position.minScrollExtent >=
          Global.screenHeight) {
        if (_scrollController.hasClients) {
          _scrollController.animateTo(
            _scrollController.position.pixels -
                Global.screenHeight +
                (Global.topHeight + 30 + 20),
            duration: const Duration(milliseconds: 200),
            curve: Curves.linear,
          );
        }
      } else {
        if (_scrollController.hasClients) {
          _scrollController.animateTo(
            _scrollController.position.minScrollExtent,
            duration: const Duration(milliseconds: 200),
            curve: Curves.linear,
          );
        }
      }
    } else {
      /// 下边触摸
      if (_scrollController.position.maxScrollExtent -
              _scrollController.position.pixels >=
          Global.screenHeight) {
        if (_scrollController.hasClients) {
          _scrollController.animateTo(
            _scrollController.position.pixels +
                Global.screenHeight -
                (Global.topHeight + 30 + 20),
            duration: const Duration(milliseconds: 200),
            curve: Curves.linear,
          );
        }
      } else {
        if (_scrollController.hasClients) {
          _scrollController.animateTo(
            _scrollController.position.maxScrollExtent,
            duration: const Duration(milliseconds: 200),
            curve: Curves.linear,
          );
        }
      }
    }
  }

  @override
  void dispose() {
    _scrollController.dispose();
    if (novelDialogHasShowEvent != null) {
      novelDialogHasShowEvent!.cancel();
    }
    super.dispose();
  }

  ///设置占位控件的高度
  addSeatWidget() {
    //如果总的列表高度-前一个填充高度还是小于屏幕高度减顶部高度,重新计算填充的高度
    if (getDoubleListHeight() - seatHeight <=
        Global.screenHeight - paddingSize - getHeadHeight()) {
      //getDoubleListHeight()就是总屏幕,可以说是包括占位符的了,如果它小于全屏-padding-头部,说明是第一次进来,没设置占位符
      // 全屏减顶部等于列表高度,如果第一次进来没满屏幕,就填充
      if (getDoubleListHeight() <=
          Global.screenHeight - paddingSize - getHeadHeight()) {
        seatHeight = Global.screenHeight -
            paddingSize -
            getHeadHeight() -
            getDoubleListHeight() +
            10;
      } else {
        //加上占位已经满屏幕了,但数据没满屏幕,重新计算占位高度。或者数据本身已经满屏幕了,这时就可以隐藏占位符
        if (getDoubleListHeight() - seatHeight <=
            Global.screenHeight - paddingSize - getHeadHeight()) {
          //实际列表高度小于屏幕高度
          seatHeight = Global.screenHeight -
              paddingSize -
              getHeadHeight() -
              (getDoubleListHeight() - seatHeight) +
              10;
        } else {
          //实际列表高度大于屏幕高度
          showSeat = false;
          mySetState(() {});
        }
      }
      showSeat = true;
      mySetState(() {});
    } else {
      //隐藏占位
      showSeat = false;
      mySetState(() {});
    }
    if (showSeat == true) {
      //数据还没满屏,要让顶部有距离
      if (_scrollController.hasClients) {
        //添加数据后,当前位置等于0,即在顶部的时候才预留顶部位置
        if (_scrollController.position.pixels ==
            _scrollController.position.minScrollExtent) {
          _scrollController
              .jumpTo(_scrollController.position.minScrollExtent + 1);
        }
      }
    }
  }

  //每次添加数据都获取两个列表的高度,小于599就填充内容
  double getDoubleListHeight() {
    double listHUp = 0.0;
    double listHDown = 0.0;
    final upListHeight = listGlobalUpKey.currentContext
        ?.findRenderObject()
        ?.semanticBounds
        .size
        .height;

    final downListHeight = listGlobalDownKey.currentContext
        ?.findRenderObject()
        ?.semanticBounds
        .size
        .height;

    if (upListHeight != null) {
      listHUp = upListHeight;
    }
    if (downListHeight != null) {
      listHDown = downListHeight;
    }
    PrintUtil.prints('列表高度123 $listHUp  $listHDown');

    return listHUp + listHDown;
  }

  //获取底部列表的高度
  getDownListHeight(){
    double listHDown = 0.0;
    final downListHeight = listGlobalDownKey.currentContext
        ?.findRenderObject()
        ?.semanticBounds
        .size
        .height;
    if (downListHeight != null) {
      listHDown = downListHeight;
    }
    PrintUtil.prints('底部列表$listHDown');
    return listHDown;
  }

  //获取头部高度
  getHeadHeight() {
    double height = 0.0;
    //顶部高度
    final containerHeight = _globalKey.currentContext?.size?.height;

    if (containerHeight != null) {
      height = containerHeight;
    }
    PrintUtil.prints('头部的距离是$height');
    return height;
  }

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Stack(
        alignment: Alignment.bottomCenter,
        children: [
          Container(
              decoration: const BoxDecoration(
                  image: DecorationImage(
                      image: AssetImage('assets/images/bg_novel_read.png'),
                      fit: BoxFit.fill // 完全填充
                      )),
              //列表的高度=全局高度-paddingSize20-顶部59=599
              padding: EdgeInsets.only(bottom: paddingSize),
              child: Column(
                children: [
                  addHeadView(),
                  Expanded(
                    child: GestureDetector(
                      onTapUp: _onTapDown,
                      child: CustomScrollView(
                        controller: _scrollController,
                        //就是这个centerKey让两个列表区分开来,拉上一页的时候不会跳到顶部
                        center: centerKey,
                        slivers: [
                          SliverToBoxAdapter(
                              child: Column(
                            key: listGlobalUpKey,
                            mainAxisAlignment: MainAxisAlignment.start,
                            children: [
                              MediaQuery.removePadding(
                                  removeTop: true,
                                  context: context,
                                  child: ListView.builder(
                                      itemCount: novelContentUpList.length,
                                      physics:
                                          const NeverScrollableScrollPhysics(),
                                      shrinkWrap: true,
                                      itemBuilder:
                                          (BuildContext context, int index) {
                                        return Container(
                                          margin: EdgeInsets.only(
                                              left: 16.r, right: 16.r),
                                          padding:
                                              EdgeInsets.only(bottom: 20.r),
                                          child: Column(
                                            crossAxisAlignment:
                                                CrossAxisAlignment.start,
                                            mainAxisAlignment:
                                                MainAxisAlignment.start,
                                            children: [
                                              //下拉加载下一页,列表拼接,显示对象里的文本字段
                                              Container(
                                                alignment:
                                                    Alignment.centerLeft,
                                                padding: EdgeInsets.only(
                                                    bottom: 15.0.r,
                                                    top: 30.r),
                                                child: Text(
                                                  novelContentUpList[index]
                                                          .title ??
                                                      '',
                                                  style: TextStyle(
                                                      color: const Color(
                                                          0xFF222222),
                                                      fontSize: 24.sp),
                                                ),
                                              ),
                                              Text(
                                                  novelContentUpList[index]
                                                          .content ??
                                                      '',
                                                  style: TextStyle(
                                                      color: const Color(
                                                          0xFF222222),
                                                      fontSize: 20.sp,
                                                      height: 2.2,
                                                      letterSpacing: 1.5)),
                                            ],
                                          ),
                                        );
                                      }))
                            ],
                          )),
                          SliverPadding(
                            padding: EdgeInsets.zero,
                            key: centerKey,
                          ),
                          SliverToBoxAdapter(
                              child: Column(
                            key: listGlobalDownKey,
                            mainAxisAlignment: MainAxisAlignment.start,
                            children: [
                              MediaQuery.removePadding(
                                  removeTop: true,
                                  context: context,
                                  child: ListView.builder(
                                      itemCount: novelContentDownList.length,
                                      physics:
                                          const NeverScrollableScrollPhysics(),
                                      shrinkWrap: true,
                                      itemBuilder:
                                          (BuildContext context, int index) {
                                        return Container(
                                          margin: EdgeInsets.only(
                                              left: 16.r, right: 16.r),
                                          padding:
                                              EdgeInsets.only(bottom: 20.r),
                                          child: Column(
                                            crossAxisAlignment:
                                                CrossAxisAlignment.start,
                                            mainAxisAlignment:
                                                MainAxisAlignment.start,
                                            children: [
                                              //下拉加载下一页,列表拼接,显示对象里的文本字段
                                              Container(
                                                alignment:
                                                    Alignment.centerLeft,
                                                padding: EdgeInsets.only(
                                                    bottom: 15.0.r,
                                                    top: 30.r),
                                                child: Text(
                                                  novelContentDownList[index]
                                                          .title ??
                                                      '',
                                                  style: TextStyle(
                                                      color: const Color(
                                                          0xFF222222),
                                                      fontSize: 24.sp),
                                                ),
                                              ),
                                              Text(
                                                  novelContentDownList[index]
                                                          .content ??
                                                      '',
                                                  style: TextStyle(
                                                      color: const Color(
                                                          0xFF222222),
                                                      fontSize: 20.sp,
                                                      height: 2.2,
                                                      letterSpacing: 1.5)),
                                            ],
                                          ),
                                        );
                                      }))
                            ],
                          )),
                          if (showSeat)
                            SliverToBoxAdapter(
                              child: GestureDetector(
                                onTapUp: seatWidgetTap,
                                child: Container(
                                  height: seatHeight,
                                  color: Colors.transparent,
                                ),
                              ),
                            )
                          //用SliverList获取不到列表的高度,所以用SliverToBoxAdapter
                          // Container(
                          //   key: listGlobalUpKey,
                          //   child: SliverList(
                          //     delegate: SliverChildBuilderDelegate(
                          //       (BuildContext context, int index) {
                          //         return Container(
                          //           color: Colors.blue,
                          //           margin: EdgeInsets.only(
                          //               left: 16.r, right: 16.r),
                          //           padding: EdgeInsets.only(bottom: 20.r),
                          //           child: Column(
                          //             crossAxisAlignment:
                          //                 CrossAxisAlignment.start,
                          //             mainAxisAlignment:
                          //                 MainAxisAlignment.start,
                          //             children: [
                          //               //下拉加载下一页,列表拼接,显示对象里的文本字段
                          //               Container(
                          //                 alignment: Alignment.centerLeft,
                          //                 padding: EdgeInsets.only(
                          //                     bottom: 15.0.r, top: 30.r),
                          //                 child: Text(
                          //                   novelContentUpList[index].title ??
                          //                       '',
                          //                   style: TextStyle(
                          //                       color:
                          //                           const Color(0xFF222222),
                          //                       fontSize: 24.sp),
                          //                 ),
                          //               ),
                          //               Text(
                          //                   novelContentUpList[index]
                          //                           .content ??
                          //                       '',
                          //                   style: TextStyle(
                          //                       color:
                          //                           const Color(0xFF222222),
                          //                       fontSize: 20.sp,
                          //                       height: 2.2,
                          //                       letterSpacing: 1.5)),
                          //             ],
                          //           ),
                          //         );
                          //       },
                          //       childCount: novelContentUpList.length,
                          //     ),
                          //   ),
                          // ),

                          // Container(
                          //   // key: listGlobalDownKey,
                          //   child: SliverList(
                          //     delegate: SliverChildBuilderDelegate(
                          //       (BuildContext context, int index) {
                          //         return Container(
                          //           color: Colors.red,
                          //           margin: EdgeInsets.only(
                          //               left: 16.r, right: 16.r),
                          //           padding: EdgeInsets.only(bottom: 20.r),
                          //           child: Column(
                          //             crossAxisAlignment:
                          //                 CrossAxisAlignment.start,
                          //             mainAxisAlignment:
                          //                 MainAxisAlignment.start,
                          //             children: [
                          //               //下拉加载下一页,列表拼接,显示对象里的文本字段
                          //               Container(
                          //                 alignment: Alignment.centerLeft,
                          //                 padding: EdgeInsets.only(
                          //                     bottom: 15.0.r, top: 30.r),
                          //                 child: Text(
                          //                   novelContentDownList[index]
                          //                           .title ??
                          //                       '',
                          //                   style: TextStyle(
                          //                       color:
                          //                           const Color(0xFF222222),
                          //                       fontSize: 24.sp),
                          //                 ),
                          //               ),
                          //               Text(
                          //                   novelContentDownList[index]
                          //                           .content ??
                          //                       '',
                          //                   style: TextStyle(
                          //                       color:
                          //                           const Color(0xFF222222),
                          //                       fontSize: 20.sp,
                          //                       height: 2.2,
                          //                       letterSpacing: 1.5)),
                          //             ],
                          //           ),
                          //         );
                          //       },
                          //       childCount: novelContentDownList.length,
                          //     ),
                          //   ),
                          // ),
                        ],
                      ),
                    ),
                  ),
                ],
              )),
          showLoading
              ? Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Container(
                      padding: EdgeInsets.only(bottom: 3.r),
                      alignment: Alignment.center,
                      width: 16.r,
                      height: 16.r,
                      child: const LoadingIndicator(
                          indicatorType: Indicator.circleStrokeSpin,

                          /// Required, The loading type of the widget
                          colors: [Color(0xFFFF4E68)],

                          /// Optional, The color collections
                          strokeWidth: 2,

                          /// Optional, The stroke of the line, only applicable to widget which contains line
                          backgroundColor: Colors.transparent,

                          /// Optional, Background of the widget
                          pathBackgroundColor: Color(0xCCFFFFFF)

                          /// Optional, the stroke backgroundColor
                          ),
                    ),
                  ],
                )
              : Container()
        ],
      ),
    );
  }

  Widget addHeadView() {
    return Container(
        key: _globalKey,
        padding:
            EdgeInsets.only(top: Global.topHeight + 10, left: 12.r, right: 5.r),
        child: Row(children: [
          GestureDetector(
            onTap: () {
              Navigator.pop(context);
            },
            child: const Image(
              image: AssetImage('assets/images/icon_back@2x.png'),
              width: 24,
              height: 25,
              color: Colors.black,
            ),
          ),
          LimitedBox(
            maxWidth: Global.screenWidth - 50,
            child: Text(
              "${widget.novelName}",
              style: const TextStyle(color: Color(0xFF222222), fontSize: 16),
              maxLines: 1,
              overflow: TextOverflow.ellipsis,
            ),
          )
        ]));
  }
}

关键代码是

CustomScrollView(
                        controller: _scrollController,
                        //就是这个centerKey让两个列表区分开来,拉上一页的时候不会跳到顶部
                        center: centerKey,
                        slivers: [
                          SliverToBoxAdapter(
                              child: Column(
                            key: listGlobalUpKey,
                            mainAxisAlignment: MainAxisAlignment.start,
                            children: [
                              MediaQuery.removePadding(
                                  removeTop: true,
                                  context: context,
                                  child: ListView.builder(
                                      itemCount: novelContentUpList.length,
                                      physics:
                                          const NeverScrollableScrollPhysics(),
                                      shrinkWrap: true,
                                      itemBuilder:
                                          (BuildContext context, int index) {
                                        return Container(
                                          margin: EdgeInsets.only(
                                              left: 16.r, right: 16.r),
                                          padding:
                                              EdgeInsets.only(bottom: 20.r),
                                          child: Column(
                                            crossAxisAlignment:
                                                CrossAxisAlignment.start,
                                            mainAxisAlignment:
                                                MainAxisAlignment.start,
                                            children: [
                                              //下拉加载下一页,列表拼接,显示对象里的文本字段
                                              Container(
                                                alignment:
                                                    Alignment.centerLeft,
                                                padding: EdgeInsets.only(
                                                    bottom: 15.0.r,
                                                    top: 30.r),
                                                child: Text(
                                                  novelContentUpList[index]
                                                          .title ??
                                                      '',
                                                  style: TextStyle(
                                                      color: const Color(
                                                          0xFF222222),
                                                      fontSize: 24.sp),
                                                ),
                                              ),
                                              Text(
                                                  novelContentUpList[index]
                                                          .content ??
                                                      '',
                                                  style: TextStyle(
                                                      color: const Color(
                                                          0xFF222222),
                                                      fontSize: 20.sp,
                                                      height: 2.2,
                                                      letterSpacing: 1.5)),
                                            ],
                                          ),
                                        );
                                      }))
                            ],
                          )),
                          SliverPadding(
                            padding: EdgeInsets.zero,
                            key: centerKey,
                          ),
                          SliverToBoxAdapter(
                              child: Column(
                            key: listGlobalDownKey,
                            mainAxisAlignment: MainAxisAlignment.start,
                            children: [
                              MediaQuery.removePadding(
                                  removeTop: true,
                                  context: context,
                                  child: ListView.builder(
                                      itemCount: novelContentDownList.length,
                                      physics:
                                          const NeverScrollableScrollPhysics(),
                                      shrinkWrap: true,
                                      itemBuilder:
                                          (BuildContext context, int index) {
                                        return Container(
                                          margin: EdgeInsets.only(
                                              left: 16.r, right: 16.r),
                                          padding:
                                              EdgeInsets.only(bottom: 20.r),
                                          child: Column(
                                            crossAxisAlignment:
                                                CrossAxisAlignment.start,
                                            mainAxisAlignment:
                                                MainAxisAlignment.start,
                                            children: [
                                              //下拉加载下一页,列表拼接,显示对象里的文本字段
                                              Container(
                                                alignment:
                                                    Alignment.centerLeft,
                                                padding: EdgeInsets.only(
                                                    bottom: 15.0.r,
                                                    top: 30.r),
                                                child: Text(
                                                  novelContentDownList[index]
                                                          .title ??
                                                      '',
                                                  style: TextStyle(
                                                      color: const Color(
                                                          0xFF222222),
                                                      fontSize: 24.sp),
                                                ),
                                              ),
                                              Text(
                                                  novelContentDownList[index]
                                                          .content ??
                                                      '',
                                                  style: TextStyle(
                                                      color: const Color(
                                                          0xFF222222),
                                                      fontSize: 20.sp,
                                                      height: 2.2,
                                                      letterSpacing: 1.5)),
                                            ],
                                          ),
                                        );
                                      }))
                            ],
                          )),
                          if (showSeat)
                            SliverToBoxAdapter(
                              child: GestureDetector(
                                onTapUp: seatWidgetTap,
                                child: Container(
                                  height: seatHeight,
                                  color: Colors.transparent,
                                ),
                              ),
                            )
                          //用SliverList获取不到列表的高度(列表高度不够满屏,滑动监听不了),所以用SliverToBoxAdapter
                        ],
                      ),
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值