Flutter--复杂内容的滚动列表实现

385 阅读1分钟

有时候在一个滚动页面里面会显示各种复杂的内容,并非一个单一列表。 比如这个页面在一个有序列表上方有一个输入框,并且用标题分割开 WechatIMG197.png

那么ListVew组件不再适用,这时候需要使用Flutter提供的CustomScrollView,各种系统滚动组件都是基于这个做的,它的必要参数是 final List<Widget> slivers;,这里有个小坑就是它的内部元素不是任意Widget,比如你直接添加Text()进入是会报错的,一般Widget可以用SliverToBoxAdapter包装一下,特殊的PaddingSliverPaddingListSliverList

这里不再一一列举,重点说一下使用有序列表的重要参数delegate,如果你不知道怎么写,可以直接去看系统ListView.builder,ListView.separated,都实现这个代理。

最后演示我上面这个例子的主要代码

@override
Widget build(BuildContext context) {
  int itemCount = 6;
  SliverChildBuilderDelegate childrenDelegate = SliverChildBuilderDelegate(
    (context, index) {
      final int itemIndex = index ~/ 2;
      final Widget? widget;
      if (index.isEven) {
        widget = Container(
          alignment: AlignmentDirectional.center,
          child: Text("$itemIndex"),
        );
      } else {
        widget = Container(
          height: 16.w,
          decoration: BoxDecoration(
            border: Border(top: BorderSide(color: AppColors.grey_color100, width: 1.w))
          ),
        );
        assert(() {
          if (widget == null) {
            throw FlutterError('separatorBuilder cannot return null.');
          }
          return true;
        }());
      }
      return widget;
    },
    childCount: max(0, itemCount * 2 - 1),
    addAutomaticKeepAlives: true,
    addRepaintBoundaries: true,
    addSemanticIndexes: true,
  );
  
  return Scaffold(
    appBar: AppBar(),
    body: Padding(
      padding: EdgeInsets.symmetric(horizontal: 16.w),
      child: CustomScrollView(
        slivers: [
          SliverPadding(padding: EdgeInsets.only(bottom: 16.w)),
          SliverToBoxAdapter(
            child: title("自定义评分体验"),
          ),
          SliverToBoxAdapter(
            child: inputView(),
          ),
          SliverToBoxAdapter(
            child: title("选择纬度(3~6个)"),
          ),
          SliverList(delegate: childrenDelegate),
          SliverPadding(padding: EdgeInsets.only(bottom: 16.w)),
        ],
      ),
    ),
  );
}

Widget title(String text) {
  return Text(
    text,
    style: AppTextStyles.body2_12_Regular.color_font_color_secondary,
  );
}

Widget inputView() {
  return TextField();
}