Since using getX, I have decided to abandon provider because getX smells too good. The following is a record of the use of getX in the scrolling loading process. This article is translated from medium. The original address: anangnugraha.medium.com/flutter-imp…

Just began to learn writing, the level of worry, writing teaching ~~

The first is the dependency I use here, in pubspec.yaml.

#... Environment: SDK: ">=2.7.0 <3.0.0" ^3.15.0 lazy_load_scrollView: ^1.1.0 equatable: ^1.2.5 dev_dependencies: flutter_test: SDK: flutter #...Copy the code

I’m using Dio as the network request library, lazy_load_scrollView as the Listview and lazy loading.

Then look at the main function

void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return GetMaterialApp( title: 'Getx Pagination', initialBinding: ApplicationBinding(), theme: ThemeData( primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), debugShowCheckedModeBanner: false, initialRoute: '/', getPages: [GetPage(name: '/', Page: () => HomeScreen(get.find ())), // You may actually need to change this to get.put (Controller()) to initialize binding: HomeBindings()), ]); }}Copy the code

Instead of MaterialApp, I use GetMaterialApp to manage routes more conveniently. I won’t go into details here.

Creating a data model

List<UserModel> userModelFromJson(String str) => List<UserModel>.from(json.decode(str).map((x) => UserModel.fromJson(x))); String userModelToJson(List<UserModel> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson()))); class UserModel { String id; String name; String username; UserModel({this.id, this.name, this.username}); UserModel.fromJson(Map<String, dynamic> json) { id = json['id']; name = json['name']; username = json['username']; } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); data['id'] = this.id; data['name'] = this.name; data['username'] = this.username; return data; }}Copy the code

class PaginationFilter {
  int page;
  int limit;

  @override
  String toString() => 'PaginationFilter(page: $page, limit: $limit)';

  @override
  bool operator ==(Object o) {
    if (identical(this, o)) return true;

    return o is PaginationFilter && o.page == page && o.limit == limit;
  }

  @override
  int get hashCode => page.hashCode ^ limit.hashCode;
}
Copy the code
class UserRepository { Dio _dio; UserRepository( this._dio, ); Future<List<UserModel>> getUsers(PaginationFilter filter) { return _dio.get('/users', queryParameters: { 'page': filter.page, 'limit': filter.limit }).then((value) => value? .data ? .map<UserModel>( (u) => UserModel.fromJson(u), ) ?.toList()); }}Copy the code

I’m going to add controller, and I’m going to create three observable variables, and I’m just going to add.obs to the variables to make them observable, and it’s going to update the UI automatically when the value of the variable changes.

class HomeController extends GetxController {
  final UserRepository _userRepository;
  final _users = <UserModel>[].obs;
  final _paginationFilter = PaginationFilter().obs;
  final _lastPage = false.obs;

  HomeController(this._userRepository);

  List<UserModel> get users => _users.toList();
  int get limit => _paginationFilter.value.limit;
  int get _page => _paginationFilter.value.page;
  bool get lastPage => _lastPage.value;

  @override
  onInit() {
    ever(_paginationFilter, (_) => _getAllUsers());
    _changePaginationFilter(1, 15);
    super.onInit();
  }

  Future<void> _getAllUsers() async {
    final usersData = await _userRepository.getUsers(_paginationFilter.value);
    if (usersData.isEmpty) {
      _lastPage.value = true;
    }
    _users.addAll(usersData);
  }

  void changeTotalPerPage(int limitValue) {
    _users.clear();
    _lastPage.value = false;
    _changePaginationFilter(1, limitValue);
  }

  void _changePaginationFilter(int page, int limit) {
    _paginationFilter.update((val) {
      val.page = page;
      val.limit = limit;
    });
  }

  void loadNextPage() => _changePaginationFilter(_page + 1, limit);
}
Copy the code

Finally, the UI section

class HomeScreen extends StatelessWidget { final HomeController _controller; const HomeScreen(this._controller, {Key key}) : super(key: key); @override Widget build(BuildContext context) { return Container( child: Scaffold( appBar: AppBar( title: Text("GetX Pagination"), actions: [ PopupMenuButton( initialValue: _controller.limit, onSelected: (value) => _controller.changeTotalPerPage(value), itemBuilder: (context) { return [ CheckedPopupMenuItem( value: 15, checked: _controller.limit == 15, child: Text("15 / pagination"), ), CheckedPopupMenuItem( value: 25, checked: _controller.limit == 25, child: Text("25 / pagination"), ), CheckedPopupMenuItem( value: 50, checked: _controller.limit == 50, child: Text("50 / pagination"), ) ]; }) ], ), body: Obx(() => LazyLoadScrollView( onEndOfPage: _controller.loadNextPage, isLoading: _controller.lastPage, child: ListView.builder( itemCount: _controller.users.length, itemBuilder: (context, index) { final user = _controller.users[index]; return ListTile( leading: Text(user.id), title: Text(user.name), subtitle: Text(user.username), ); },),),),); }}Copy the code

Now you have a list that you can scroll to load, and the state is entirely up to GetX.