Flutter使用getX心得之滚动加载

2,760 阅读2分钟

自从使用getX以后果断嫌弃了provider,原因是getX太香了。 学习中发现中文资料还是很少,下面记录一下使用getX在滚动加载时的使用过程,本文是从medium上翻译的。 原文地址:anangnugraha.medium.com/flutter-imp…

刚开始学写作,水平堪忧,求写作教学~~

首先是我这里用到的依赖,在pubspec.yaml。

# ...

environment:
  sdk: ">=2.7.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.0
  dio: ^3.0.10
  get: ^3.15.0
  lazy_load_scrollview: ^1.1.0
  equatable: ^1.2.5

dev_dependencies:
  flutter_test:
    sdk: flutter
     
# ...

我这里使用了Dio作为网络请求库,lazy_load_scrollview作为Listview而且支持懒加载。

然后看一下main函数

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()),
              //实际上你可能需要在这里换成Get.put(Controller())进行初始化
              binding: HomeBindings()),
        ]);
  }
}

我这里使用GetMaterialApp 代替了MaterialApp,可以更方便的管理路由,这里就不多说了。

创建数据模型

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;
  }
}

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;
}
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());
  }
}

加下来是 controller,这里创建了3个可观察变量,只需要在变量后面加上.obs即可变成可观察变量,当变量值改变时自动会更新UI。

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);
}

最后是UI部分了

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),
                  );
                },
              ),
            )),
      ),
    );
  }
}

好了,这样就有了一个可以滚动加载的列表了,状态完全由GetX负责。