动画无限滚动视图

在用户向下滚动屏幕时加载并显示小块内容

pub.dev 包

概述

1- 声明扩展了 PaginationViewModel<T> 的 View-Model

  • PaginationViewModel 是 **用户界面** 和由存储库处理的 **模型** 之间的层。
  • T 是您的数据列表的类型。例如,如果您有 List<User>,您将创建一个扩展 PaginationViewModel<User> 的 **ViewModel**。

在创建 View-Model 之前,我们将创建我们的 **Repository**。Repository 是 View-Model 和后端之间的层。

Repository 将如下所示

import 'dart:async';
import 'dart:convert';
import 'package:example/config/env.dart';
import 'package:example/models/passenger.dart';
import 'package:animated_infinite_scroll_pagination/animated_infinite_scroll_pagination.dart';
import 'package:example/models/passengers_response.dart';
import 'package:http/http.dart' as http;


class PassengerRepository {
  final _controller = StreamController<PaginationState<List<Passenger>>>();

  Stream<PaginationState<List<Passenger>>> get result async* {
    yield* _controller.stream;
  }

  Future<int> getPassengersList(int page) async {
    /// emit loading
    _controller.add(const PaginationLoading());

    /// fetch data from server
    final api = "${Env.paginationApi}?page=$page&size=${Env.perPage}";
    try {
      final http.Response response = await http.get(Uri.parse(api));
      final responseData = PassengersListResponse.fromJson(jsonDecode(response.body));
      final passengers = responseData.data ?? [];

      /// emit fetched data
      _controller.add(PaginationSuccess(passengers));
      return responseData.totalPassengers ?? 0;
    } catch (_) {
      /// emit error
      _controller.add(const PaginationError());
      return 0;
    }
  }
}

现在我们将创建我们的 **View-Model**。View-Model 将如下所示

class PassengersViewModel extends PaginationViewModel<Passenger> {
	final repository = PassengerRepository();
	
	/// Sorts this list according to the order specified by the [compare] function.
	@override
	Function(Passenger  a, Passenger  b) compare = ((a, b) => a.id.toString().compareTo(b.id.toString()));

	/// sort inserted items
	@override
	bool  sortItems = false;

	/// decide whether two object represent the same Item
	@override
	bool  areItemsTheSame(Passenger  a, Passenger  b) {
		return  a.id == b.id;
	}

	/// fetch data from repository and emit by Stream to pagination-list
	///
	/// set total items count -> stop loading on last page
	@override
	Future<void> fetchData(int  page) async {
		final  total = await  repository.getPassengersList(page);
		// tell the view-model the total of items.
		// this will stop loading more data when last data-chunk is loaded
		setTotal(total); 
	}

	/// subscribe for list changes
	@override
	Stream<PaginationState<List<Passenger>>> streamSubscription() => repository.result;

	/// remove an item from passengers list
	void  remove(Passenger  passenger) {
		// `params` is a variable declared in `PaginationViewModel`
		// which contains the List<T>
		final  index = params.itemsList.value.items.indexWhere((element) => element.item.id == passenger.id);
		// `deleteItem` is a method declared in `PaginationViewModel`
		// which expected a integer value `index of item`
		if (index != -1) deleteItem(index);
	}
}

2- UI

  • 在屏幕中声明您的 view-model

final viewModel = PassengersViewModel();

@override
void initState() {
    super.initState();
    viewModel
      ..listen() // observe data-list changes when repository update the list
      ..getPaginationList(); // fetch first chunk of data from server
 }

@override
void dispose() {
    viewModel.dispose();
    super.dispose();
}
  • 将动画滚动视图包装在您的屏幕中

  deletePassenger(Passenger passenger) {
  	viewModel.remove(passenger);
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedInfiniteScrollView<Passenger>(
      viewModel: viewModel,
      loadingWidget: const AppProgressBar(), // customize your loading widget
      footerLoadingWidget: const AppProgressBar(), // customize your pagination loading widget
      errorWidget: const Text("Pagination Error"), // customize your error widget
      itemBuilder: (item) => PassengerCard(passenger: item, onDelete: deletePassenger),
      refreshIndicator: true,
    );
  }

AnimatedInfiniteScrollView 参数

  • viewModel:您在上面声明的 View-Model,例如 *(必需)*。
  • loadingWidget:当第一页加载时您想显示的 widget *(可选)*。
  • footerLoadingWidget:当分页数据加载时您想显示的 widget *(可选)*。
  • errorWidget:当分页数据加载失败(抛出异常)时您想显示的 widget *(可选)*。
  • refreshIndicator:将滚动视图包装在 RefreshIndicator 中 *(可选)*,**默认值**为 false
  • itemBuilder:一个 widget 函数,用于在滚动视图中构建您的 **数据 Widget**,针对列表中的每个 **数据项** *(必需)*。

GitHub

查看 Github