Flutter - 如何使用 SliverAppBar 和无限滚动分页?

问题描述 投票:0回答:4

我在我的 flutter 应用程序中使用 Infinite Scroll Pagination 插件。我还需要在我的页面中使用 SilverAppBar。这是我的代码:

return Scaffold(
  body: DefaultTabController(
    length: 2,
    child: NestedScrollView(
      headerSliverBuilder: (context, value) {
        return [
          SliverAppBar(
            bottom: TabBar(
              tabs: [
                Tab(icon: Icon(Icons.call), text: "1"),
                Tab(icon: Icon(Icons.message), text: "2"),
              ],
            ),
          ),
        ];
      },
      body: TabBarView(
        children: [
          const MyListWidget()
          Text('2')
        ],
      ),
    ),
  ),
);

这是我的 MyListWidget:

Widget build(BuildContext context) {
return PagedSliverList<int, MyModel>(
      pagingController: _сontroller,
      builderDelegate: PagedChildBuilderDelegate<MyModel>(
        itemBuilder: (context, item, index) {
          return Text(item.Title);
        },
      ),
    );
  }

但是我有错误:

A RenderRepaintBoundary expected a child of type RenderBox but received a child of type RenderSliverList.

我也尝试过:

body: SliverFillRemaining(
            child: TabBarView(
              children: [
                const ProfileSelections(),
                //Container(child: Text('1')),
                Text('2')
              ],
            ),
          )

但是我有错误:

 A RenderSliverFillRemainingWithScrollable expected a child of type RenderBox but received a child of type RenderSliverFillRemainingWithScrollable.

如何修复这些错误?任何建议 - 我将不胜感激

flutter dart flutter-layout infinite-scroll
4个回答
12
投票

无需使用无限滚动分页,只需使用flutter内置的滚动通知即可。

滚动通知 - 抽象类 ScrollNotification 使用 ViewportNotificationMixin 扩展 LayoutChangedNotification。

与滚动相关的通知。

可滚动小部件通知其祖先有关滚动相关的更改。

通知具有以下生命周期:

  • 一个ScrollStartNotification,表明该小部件已 开始滚动。

  • 零个或多个ScrollUpdateNotifications,这表明 小部件已更改其滚动位置,混合有零个或多个

  • OverscrollNotifications,表明该小部件尚未 更改了其滚动位置,因为该更改会导致其 滚动位置超出其滚动范围。穿插 滚动更新通知和 OverscrollNotifications 是零个或多个 UserScrollNotifications, 这表明用户已经改变了他们的方向 正在滚动。

  • ScrollEndNotification,表示小部件已停止 滚动。

  • 一个 UserScrollNotification,其 UserScrollNotification.direction 为 ScrollDirection.idle.

这是完整的源代码和解释

import 'package:flutter/material.dart';

class InfiniteScrollPagination extends StatefulWidget {
  const InfiniteScrollPagination({Key key}) : super(key: key);

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

class _InfiniteScrollPaginationState extends State<InfiniteScrollPagination> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: DefaultTabController(
        length: 2,
        child: NestedScrollView(
          headerSliverBuilder: (context, value) {
            return [
              SliverAppBar(
                pinned: true,
                toolbarHeight: 0,
                bottom: TabBar(
                  tabs: [
                    Tab(icon: Icon(Icons.call), text: "1"),
                    Tab(icon: Icon(Icons.message), text: "2"),
                  ],
                ),
              ),
            ];
          },
          body: TabBarView(
            children: [MyListWidget(), Text('2')],
          ),
        ),
      ),
    );
  }
}

class MyListWidget extends StatefulWidget {
  const MyListWidget({Key key}) : super(key: key);

  @override
  State<MyListWidget> createState() => _MyListWidgetState();
}

class _MyListWidgetState extends State<MyListWidget> {
  int count = 15;

  @override
  Widget build(BuildContext context) {
    return NotificationListener<ScrollNotification>(
      onNotification: (ScrollNotification scrollInfo) {
        if (scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) {
          // here you update your data or load your data from network
          setState(() {
            count += 10;
          });
        }
        return true;
      },
      // if you used network it would good to use the stream or future builder
      child: Container(
        child: getDataList(count),
      ),
    );
  }
}

getDataList(listOfData) {
  return ListView.separated(
      itemBuilder: (context, index) {
        return ListTile(
          title: Text("index $index"),
        );
      },
      separatorBuilder: (context, index) => Divider(
        thickness: 2,
        color: Colors.grey,
      ),
      itemCount: listOfData);
}

输出:


2
投票

发生这种情况是因为

tabBarView
需要正常的
box children
而不是
slivers
因为它默认使用页面视图,您可以在 官方文档中阅读。

如果您使用普通列表而不是像下面这样的条子,它将解决问题:

Widget build(BuildContext context) {
return  PagedListView<int, MyModel>(
      pagingController: _сontroller,
      builderDelegate: PagedChildBuilderDelegate<MyModel>(
        itemBuilder: (context, item, index) {
          return Text(item.Title);
        },
      ),
    );
  }

1
投票

使用

PagedListView
而不是
PagedSliverList
可以解决问题。 Slivers 不是小部件,并且 Slivers 以不同的方式呈现。我们主要在 CustomScrollView 小部件中使用
Slivers


0
投票

我用

SliverAppBar
SliverList.separated()
实现了无限滚动。我将它们包裹在
NotificationListener<ScrollNotification>
中,如下所示,一切都很好:

NotificationListener<ScrollNotification>(
  onNotification: (scrollNotification) {
  if (scrollNotification is ScrollEndNotification) {
    onScrollListener();
  }

  return true;
}

void onScrollListener() {
  if (reachedEnd) {
    return;
  }

  if (!isPageLoading) {
    isPageLoading = true;
    Future.microtask(() async {
      final newItems = await getItemsUseCase.get(page: nextPage);
      if (newItems.length < pageSize) {
        reachedEnd= true;
      } else {
        nextPage++;
      }

      allItems.addAll(newItems);
      isPageLoading = false;
    });
  }
}

我在这里添加了完整的代码示例

© www.soinside.com 2019 - 2024. All rights reserved.