在滚动列表视图中加载更多文章

时间:2019-10-12 18:22:16

标签: flutter dart

当用户向上滚动listview时,我正在尝试实现更多加载功能。我正在使用BloC模式,并且正在尝试使用通知侦听器。

我有以下代码:

home.dart

import 'package:flutter/material.dart';
import '../models/news_model.dart';
import '../blocs/news_bloc.dart';
import '../utils/helpers.dart';
import '../utils/constants.dart';
import 'package:html_unescape/html_unescape.dart';
import 'package:flutter_web_browser/flutter_web_browser.dart';
import 'package:intl/intl.dart';

class Home extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return HomeState();
  }
}

class HomeState extends State<Home> {
  ItemLoadMoreStatus loadMoreStatus = ItemLoadMoreStatus.STABLE;
  int currentPageNumber = 0;
  List news = new List();
  final ScrollController scrollController = new ScrollController();

  @override
  void initState() {
    super.initState();
    bloc.fetchHomeNews(currentPageNumber);
  }

  @override
  void dispose() {
    bloc.dispose();
    super.dispose();
  }

   @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Color(0xfff0f0f0),
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: StreamBuilder(
        stream: bloc.allHomeNews,
        builder: (context, AsyncSnapshot<NewsModel> snapshot) {
          if (snapshot.hasData) {
            return buildList(snapshot);
          } else if (snapshot.hasError) {
            return Text(snapshot.error.toString());
          }
          return Center(child: CircularProgressIndicator());
        },
      ),
    );
  }

  Widget buildList(AsyncSnapshot<NewsModel> snapshot) {
    news = snapshot.data.results;
    var unescape = new HtmlUnescape();

    return NotificationListener(
      onNotification: onNotification,
      child: new ListView.builder(
          itemCount: news.length,
          padding: new EdgeInsets.only(top: 5.0),
          controller: scrollController,
          itemBuilder: (context, index) {

            return Card(
                margin: new EdgeInsets.all(5.0),
                child: ListTile(
                    isThreeLine: true,
                    leading: CircleAvatar(
                      backgroundColor: Color(0xfff0f0f0),
                      foregroundColor: Constants.primaryColor,
                      child: const Icon(Constants.iconHome),
                    ),
                    title: Text(
                      unescape.convert(news[index].title),
                      style: TextStyle(fontSize: 14.0 ,fontWeight: FontWeight.w500, color: Color(0xff333333))
                    ),
                    subtitle: Column(
                      crossAxisAlignment: CrossAxisAlignment.stretch,
                      children: <Widget>[
                        Text(
                          Helpers.truncateString(unescape.convert(news[index].summary), 100),
                          style: TextStyle(fontSize:13.0, color: Color(0xff333333)),
                        ),
                        Container(
                            padding: EdgeInsets.only(top: 5.0),
                            child: Text(
                              'Published on: '+DateFormat("yyyy-MM-dd kk:mm").format(DateTime.parse(news[index].published)),
                              style: TextStyle(fontSize: 11.0, color: Color(0xff777777)),
                              textAlign: TextAlign.left,

                            ),
                        ),

                      ],
                    ),
                    onTap: () {
                      FlutterWebBrowser.openWebPage(url: news[index].link, androidToolbarColor: Constants.primaryColor);
                    },
                  ),
            );
      }),
    );

  }

  bool onNotification(ScrollNotification notification) {
    if (notification is ScrollUpdateNotification) {
      if (scrollController.position.maxScrollExtent > scrollController.offset &&
          scrollController.position.maxScrollExtent - scrollController.offset <=
              50) {
        if (loadMoreStatus != null &&
            loadMoreStatus == ItemLoadMoreStatus.STABLE) {
          //print("UPDATE LIST ON NOTIFICATION");
          loadMoreStatus = ItemLoadMoreStatus.LOADING;
          var newPage = currentPageNumber+1;
          currentPageNumber = newPage;

          setState(() {
              news.addAll(bloc.fetchHomeNews(newPage));
          });
        }
      }
    }

    return true;
  }
}

Bloc文件 news_bloc.dart

import '../resources/repository.dart';
import 'package:rxdart/rxdart.dart';
import '../models/news_model.dart';
//import '../models/home_model.dart';

class NewsBloc {
  final _repository = Repository();
  final _newsFetcher = PublishSubject<NewsModel>();
  final _homeFetcher = PublishSubject<NewsModel>();
  final _appFetcher = PublishSubject<NewsModel>();
  final _reviewsFetcher = PublishSubject<NewsModel>();

  Observable<NewsModel> get allNews => _newsFetcher.stream;
  Observable<NewsModel> get allAppNews => _appFetcher.stream;
  Observable<NewsModel> get allReviews => _reviewsFetcher.stream;
  Observable<NewsModel> get allHomeNews => _homeFetcher.stream;

  fetchAllNews() async {
    NewsModel newsModel = await _repository.fetchAllNews();
    _newsFetcher.sink.add(newsModel);
  }

  fetchHomeNews(pageNumber) async {
    NewsModel newsModel = await _repository.fetchHomeNews(pageNumber);
    _homeFetcher.sink.add(newsModel);
  }

  fetchAppNews() async {
    NewsModel newsModel = await _repository.fetchAppNews();
    _appFetcher.sink.add(newsModel);
  }

  fetchReviews() async {
    NewsModel newsModel = await _repository.fetchReviews();
    _reviewsFetcher.sink.add(newsModel);
  }

  dispose() {
    _newsFetcher.close();
    _homeFetcher.close();
    _appFetcher.close();
    _reviewsFetcher.close();
  }
}

final bloc = NewsBloc();

和新闻模型 news_model.dart

import '../utils/helpers.dart';

class NewsModel{

  List<_Result> _results = [];

  NewsModel.fromJson(feed) {
    List<_Result> temp = [];

    for (int i = 0; i < feed.length; i++) {
      _Result result = _Result(feed[i]);
      temp.add(result);
    }
    _results = temp;
  }

  List<_Result> get results => _results;
}

class _Result {
  String _title;
  String _link;
  String _published;
  String _summary;

  _Result(result) {

    _title = result.title;
    _link = result.id;
    _published = result.published;
    _summary = Helpers.removeAllHtmlTags(result.summary);

  }

  String get published => _published;
  String get title => _title;
  String get link => _link;
  String get summary => _summary;
}

问题

不幸的是,这似乎不起作用。有人可以帮我解决我做错的地方吗?

更新

如何使用NotificationListener来做到这一点?

1 个答案:

答案 0 :(得分:0)

我认为您需要将ScrollController放在initState()中。

例如,这就是我所拥有的,并且有效:

  @override
  void initState() {
    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        getMoreData();
      }
    });
    super.initState();
  }