Flutter之页面基类 2025-04-18 周五

简介

GetView不适合做基类,所以考虑模仿其写法,自己写一个页面基类。

需要修改的地方

  • tag需要作为一个变量,在构造页面的时候由外部传入。

  • 命名调整一下,我们的工程中页面习惯叫page,逻辑习惯叫logic。所以,controller的名字修改为logic

  • 一直想用Get.put()来得到logic的实例。但是Flutter Dart的反射功能不完善,所以从类型T得到T的实例有困难。由于这个原因,还是参考GetView的做法,采用Get.find()来获取logic的实例。

 T get logic => GetInstance().find<T>(tag: tag);
  • 绑定函数Get.put()如果让调用者处理,那么我在跳转页面的时候,不但要知道哪个页面,还要知道哪个logic,感觉不是很合理。所以,最后决定在构造函数中执行这个绑定函数(page的子类)。

  • 界面更新放弃Obs方式,固定使用update()方式;所以在build函数中固定包一层GetBuilder();这样就避免了页面不更新的尴尬。

  • 基类添加abstract关键字,防止实例化,这个很好,借鉴过来。

  • 鉴于页面大多使用Scaffold骨架,所以把这个也写进去,然后分为标题,body什么的让子类重写。

abstract class BasePage<T extends GetxController> extends StatelessWidget {
  const BasePage({super.key, this.tag});

  final String? tag;

  T get logic => GetInstance().find<T>(tag: tag);

  @override
  Widget build(BuildContext context) {
    return GetBuilder<T>(
      tag: tag,
      builder: (_) {
        return _buildInternal();
      },
    );
  }

  Widget _buildInternal() {
    return GBScaffold(
      title: title,
      body: buildBody(),
      actions: buildActions(),
      bottom: buildBottom(),
    );
  }

  final String title = "";

  Widget buildBody() {
    return Container();
  }

  List<Widget>? buildActions() {
    return null;
  }

  PreferredSizeWidget? buildBottom() {
    return null;
  }
}

使用的例子

  • 比如购物车,我们首先写一个继承自GetxController的logic
class CartLogic extends GetxController {
}
  • 再写一个继承自BasePage的Page
class CartPage extends BasePage<CartLogic> {
  CartPage({super.key, super.tag}) {
    Get.put(CartLogic(), tag: tag);
  }

  @override
  String get title => "tab_cart".tr;

  @override
  Widget buildBody() {
    return Column(
      children: [
        messageRow(),
        logic.dataList.isNotEmpty
            ? Expanded(child: listWidget())
            : Expanded(
            child: Kong(
              img: R.assetsImgKongNocontent,
              title: logic.dataReady ? 'cart_empty_tip'.tr : "",
            )),
        operatorWidget(),
      ],
    );
  }
}
  • 绑定函数Get.put(CartLogic(), tag: tag)在构造函数中执行,只执行一次

  • 大多数情况,重写title和body就可以了,进行具体的页面布局。在Page中,要访问CartLogic的成员,直接使用logic.就可以了。基类BasePage使用了Get.find()来得到这个实例。这样就保证了put()和find()方法的对应,避免了put()方法的遗漏。

  • 等Flutter Dart良好支持反射的时候,将put()方法移到基类BasePage中就更好了。

页面如何跳转?

可以将页面跳转封装成一个独立的方法,方便调用。由于购物车需要logic和view的对应,所以考虑用时间戳作为tag,保证不会重复,避免出现多个Page对应同一个logic的情况。

  /// 打开购物车页面
  static void openCart() {
    String tag = 'cart${DateTime.now().microsecondsSinceEpoch}';
    Get.to(() => CartPage(tag: tag));
  }
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容