Player Mayan
Player Mayan

Reputation: 51

how to add onscroll fetch data (pagination) in flutter & firebase realtime?

Hope Well,

I am using firebase realtime database on my flutter app (similar social media app). i have feed page and feed state page. i wanna show 10 posts first and after scroll bottom, load again 10 posts. i tried some methods but not working.

my codes

feed page code

  Widget build(BuildContext context) {
    var authstate = Provider.of<AuthState>(context, listen: false);
    return Consumer<FeedState>(
      builder: (context, state, child) {
        final List<FeedModel> list = state.getPostList(authstate.userModel);
        return CustomScrollView(
          slivers: <Widget>[
            child,
            state.isBusy && list == null
                ? SliverToBoxAdapter(
                    child: Container(
                      height: fullHeight(context) - 135,
                      child: CustomScreenLoader(
                        height: double.infinity,
                        width: fullWidth(context),
                        backgroundColor: Colors.white,
                      ),
                    ),
                  )
                : !state.isBusy && list == null
                    ? SliverToBoxAdapter(
                        child: EmptyList(
                          'Follow someone',
                          subTitle:
                              'goto search page to find & follow Someone.\n When they added new post,\n they\'ll show up here.',
                        ),
                      )
                    : SliverList(
                        delegate: SliverChildListDelegate(
                          list.map(
                            (model) {
                              return Container(
                                color: Colors.white,
                                child: Post(
                                  model: model,
                                  trailing: PostBottomSheet().PostOptionIcon(
                                      context,
                                      model: model,
                                      type: PostType.Post,
                                      scaffoldKey: scaffoldKey),
                                ),
                              );
                            },
                          ).toList(),
                        ),
                      )
          ],
        );
      },

feed state code

List<FeedModel> get feedlist {
    if (_feedlist == null) {
      return null;
    } else {
      return List.from(_feedlist.reversed);
    }
  }

  List<FeedModel> getPosttList(UserModel userModel) {
    if (userModel == null) {
      return null;
    }
    return feedlist;
  }

Upvotes: 0

Views: 779

Answers (1)

Patrick O&#39;Hara
Patrick O&#39;Hara

Reputation: 2229

I modified your code and use a ScrollController to load more data when the user reaches the end of the loaded data. (The data provider is hard-coded but you should be able to relate it to your scenario.) Note that I changed your code to use SliverChildBuilderDelegate which is more efficient.

import 'package:flutter/material.dart';

class ScrollTest extends StatefulWidget {
  @override
  _ScrollTestState createState() => _ScrollTestState();
}

class _ScrollTestState extends State<ScrollTest> {
  bool isLoading = false;
  bool isEnd = false;
  final List<FeedModel> list = [];

  ScrollController _controller;

  _scrollListener() async {
    var position = _controller.offset /
        (_controller.position.maxScrollExtent -
            _controller.position.minScrollExtent);
    if (position > 0.5 && !_controller.position.outOfRange) {
      await _getMoreData(list.length);
    }
  }

  @override
  void initState() {
    super.initState();
    _controller = ScrollController();
    _controller.addListener(_scrollListener);
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _getMoreData(list.length);
  }

  Future<void> _getMoreData(int index) async {
    if (!isLoading) {
      setState(() {
        isLoading = true;
      });

      var tlist = await Feed.getPostList(index);

      setState(() {
        if (tlist.length == 0) {
          isEnd = true;
        } else {
          list.addAll(tlist);
          index = list.length;
        }

        isLoading = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      controller: _controller,
      slivers: <Widget>[
        SliverList(
          delegate: SliverChildBuilderDelegate(
            (BuildContext context, int index) {
              return Container(
                color: Colors.white,
                height: 300,
                child: Text(list[index].text),
              );
            },
            childCount: list.length,
          ),
        ),
        SliverFillRemaining(
            child: Center(
          child: isEnd ? Text('End') : CircularProgressIndicator(),
        )),
      ],
    );
  }
}

// Dummy FeedModel
class FeedModel {
  final String text;
  FeedModel(this.text);
}

// Dummy Feed provider
class Feed {
  static final data = [
    FeedModel('1'),FeedModel('2'),FeedModel('3'),FeedModel('4'),
    FeedModel('5'),FeedModel('6'),FeedModel('7'),FeedModel('8'),
    FeedModel('9'),FeedModel('10'),FeedModel('11'),FeedModel('12'),
    FeedModel('13'),
  ];

  static Future<List<FeedModel>> getPostList(int index) async {
    List<FeedModel> l = [];
    for (var i = index; i < index + 5 && i < data.length; i++) {
      l.add(data[i]);
    }
    await Future.delayed(Duration(seconds: 1));
    return l;
  }
}

Upvotes: 1

Related Questions