Flutter状态管理--GetX的简单使用

Posted 建古

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter状态管理--GetX的简单使用相关的知识,希望对你有一定的参考价值。

一、前言
Flutter开发,就需要对各种状态的管理,就是在请求数据的时候需要实时变化,各种交互变化等,在没有使用GetX之前使用Provider,用Provider的时候觉得真香,挺方便的,需要刷新的时候直接 notifyListeners(); 用了GetX之后觉得Provider太繁琐了。这边介绍下GetX的使用以及常用的方法。

二、 GetX
GetX 是 Flutter 上的一个轻量且强大的解决方案:高性能的状态管理、智能的依赖注入和便捷的路由管理。
1、相关优势:

1、轻量,可以模块单独编译,没有用到的功能不会编译进我们的代码
2、刷新简单,
第一种自动刷新 Obx(() => Text())
第二中手动刷新 update()
3、跨页面交互
4、路由管理
	getx内部实现了路由管理,这个是非常重要的,这样我们就不需要使用其他第三插件,之前都是使用fluro,现在直接不用了,而且getx的路由管理真的真的非常简单。代码也简洁。
6、国际化、主题的适配
7、获取全局的BuildContext  这个也是比较喜欢的地方,很多时候弹窗或者其他地方,需要拿到上下文,使用getx,直接获取。方便至极
8、依然注入

三、使用
1、第一步 引入get

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.2
  get: ^4.1.4

2、第二步
修改入口、配置路由

@override
  Widget build(BuildContext context) {
  	// 只需要将MaterialApp改成GetMaterialAp
    return GetMaterialApp(
      title: 'GetX使用',
      debugShowCheckedModeBanner: false,
      enableLog: true,
      initialRoute: '/', //根路由
      getPages: Pages.routes, // 配置路由
      defaultTransition:
          Utils.isios() ? Transition.native : Transition.rightToLeft, // 转场动画
      themeMode: ThemeMode.system, // 主题
      darkTheme: ThemeData.dark(),
      theme: ThemeConfig.lightTheme,
      home: SplashPage(),
      builder: (context, child) {
        return Scaffold(
            body: GestureDetector(
          onTap: () {
            hideKeyboard(context);
          },
          child: FlutterEasyLoading(child: child),
        ));
      },
    );
  }

3、路由

/// 跳转新页面
/// 第一种方式 进入新页面 直接页面
Get.to(ProjectCloudVisiblePage());
/// 第二种方式 进入新页面 配置路由名称  建议这种统一配置
Get.toNamed(Routes.PROJECT_CLOUD_SELECT_MEMBERS);
///弹出当前页,并将一个新的[page]推入堆栈,就是删除就页面,使用新页面
Get.off(ProjectCloudVisiblePage());
/// Push a [page]和弹出几个页面在堆栈中,就是进入新页面,删除之前进栈的页面。比如场景(注册-手机号-其他注册信息-注册完了直接到主页,之前页面全部删掉。)
Get.offAll(ProjectCloudVisiblePage());
/// 同上,就是传路由名称
Get.offAllNamed(FXRoutes.PROJECT_CLOUD_SELECT_MEMBERS);
返回上一面 就一句
Get.back()

Routes类

abstract class Routes {
  static const INITIAL = '/';
  static const GUIDE = '/guide';
  static const LOGIN = '/login';
  static const CODE_LOGIN = '/code_login';
  static const INPUT_CODE = '/input_code';
  static const FORGET_PASSWORD = '/forget_password';
  static const REGISTER = '/register';
  static const PROJECT_CLOUD_VISIBLE = 'project_cloud_visible';
}

Pages类

class Pages {
  static const INITIAL = FXRoutes.INITIAL;
  static final routes = [
    GetPage(
        name: Routes.GUIDE,
        page: () => SplashPage(),
        transition: Transition.fadeIn),
    GetPage(
        name: Routes.INITIAL,
        page: () => LoginPage(),
        transition: Transition.fadeIn),
    GetPage(
        name: Routes.LOGIN,
        page: () => LoginPage(),
        transition: Transition.fadeIn),
    GetPage(
        name: Routes.CODE_LOGIN,
        page: () => CodeLoginPage(),
        transition: Transition.fadeIn),
    GetPage(name: Routes.INPUT_CODE, page: () => InputCodePage()),
    /// 这边使用依赖注入
    GetPage(
        name: FXRoutes.PROJECT_CLOUD_VISIBLE,
        page: () => ProjectCloudVisiblePage(),
        binding: BindingsBuilder(() => {
              Get.lazyPut<ProjectCloudVisibleController>(
                  () => ProjectCloudVisibleController())
            })),
}

4、状态管理
我一般一个page对应一个controller, controller来处理逻辑,控制page.
简单使用

/// 
controller 要继承 GetxController
class ProjectCloudListSearchController extends GetxController {
  List<String> searchRecords = [];
  TextEditingController editingController;
  String searchText;
  List<String> dataList = [];

  @override
  void onInit() {
    // TODO: implement onInit
    super.onInit();
    editingController = TextEditingController();

    /// 获取历史记录
    ProjectCloudSearchCache.getProjectCloudSearchList().then((value) {
      searchRecords.addAll(value);
      update();
    });
  }

  @override
  void onClose() {
    // TODO: implement onClose
    super.onClose();

    /// 添加缓存
    ProjectCloudSearchCache.setProjectCloudSearchList(searchRecords);
  }

  /// 搜索请求 处理缓存
  void searchRequest(String text,
      {bool isRequest = true, bool clickRecords = false}) {
    Utils.logs(text);
    searchText = text;

    if (clickRecords) {
      editingController.text = text;
    }

    /// 请求接口
    if (isRequest) {
      dataList.add('1');
      searchRecordsHandle();
    }
    update();
  }

  /// 删除记录
  void deleteRecord(int index) {
    searchRecords.removeAt(index);
    update();
  }

  /// 清空记录
  void clearRecords() {
    searchRecords.clear();
    /// 手动刷新 调用update
    update();
  }

  /// 搜索记录处理
  void searchRecordsHandle() {
    if (searchText.isNotEmpty) {
      if (!searchRecords.contains(searchText)) {
        if (searchRecords.length >= 10) {
          searchRecords.removeLast();
        }
        searchRecords.insert(0, searchText);
      }
    }
  }
}
/// page页面
class ProjectCloudListSearchPage extends StatefulWidget {
  @override
  _ProjectCloudListSearchPageState createState() =>
      _ProjectCloudListSearchPageState();
}

class _ProjectCloudListSearchPageState
    extends State<ProjectCloudListSearchPage> {
  FocusNode _focusNode = FocusNode();
  /// 注入依赖 使用Get.put
  final _searchC = Get.put(ProjectCloudListSearchController());
  @override
  void initState() {
    // TODO: implement init State
    super.initState();
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _focusNode.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: FXColor.color_text_66,
      appBar: SearchWidget(
        _searchC.editingController,
        focusNode: _focusNode,
        searchHintText: '输入作品标题',
        searchCallBack: (searchText) {
          _focusNode.unfocus();
          _searchC.searchRequest(searchText);
        },
        onChanged: (searchText) {
          _searchC.searchRequest(searchText, isRequest: false);
        },
      ),
      /// 使用GetBuilder包裹起来 调用update的时候 这边就会自动刷新数据。
      body: GetBuilder<ProjectCloudListSearchController>(builder: (_) {
        return EmptyUtils.isEmptyString(_searchC.searchText) &&
                _searchC.searchRecords.isNotEmpty
            ? ProjectCloudSearchRecordsWidget(
                _searchC.searchRecords,
                valueCallBack: (searchText) {
                  _focusNode.unfocus();
                  _searchC.searchRequest(searchText, clickRecords: true);
                },
                deleteRecordCallBack: (index) {
                  _searchC.deleteRecord(index);
                },
                clearRecordCallBack: () {
                  _searchC.clearRecords();
                },
              )
            : _searchC.dataList.isEmpty
                ? NoDataWidget()
                : ListView.builder(
                    padding: const EdgeInsets.only(top: 10),
                    itemCount: 5,
                    itemBuilder: (context, index) {
                      return ProjectCloudListWidget();
                    });
      }),
    );
  }
}

5、依赖注入
依赖注入也是我喜欢的,可以减少很多工作。
第一步

GetPage(
        name: FXRoutes.PROJECT_CLOUD_VISIBLE,
        page: () => ProjectCloudVisiblePage(),
        /// 主要代码是这个 绑定
        binding: BindingsBuilder(() => {
              Get.lazyPut<ProjectCloudVisibleController>(
                  () => ProjectCloudVisibleController())
            })),

第二步

/// 页面继承GetView<> 传依赖注入的控制器 这样就可以直接使用了,会发现这边没有 Get.put,或者Git.find, 使用的时候直接controller。 看源码可以知道GetView内部已经帮我们实现了。
class ProjectCloudVisiblePage extends GetView<ProjectCloudVisibleController> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBarWidget(
        '谁可见',
        context: context,
        actions: [
          Container(
            margin: const EdgeInsets.only(right: 15),
            child: TextWidget(
              '保存',
              style: TextStyles.setTextStyle14(color: FXColor.blue_color),
              clickCallBack: () {
              /// 直接使用 controller
                controller.saveVisibleSetting();
              },
            ),
          )
        ],
      ),
      body: Column(
        children: [
          ProjectCloudSettingItemWidget(
            '公开',
            isSelect: false,
            clickCallBack: () {
              controller.allMemberVisitingSetting();
            },
          ),
          ProjectCloudSettingItemWidget(
            '部分可见',
            isSelect: true,
            subText: '从组织架构中选择 >',
            isShowDivider: false,
            clickCallBack: () {
              controller.pushToSelectMembers();
            },
          ),
          GetBuilder<ProjectCloudVisibleController>(builder: (_) {
            return Container(
              color: Colors.white,
              padding: const EdgeInsets.only(bottom: 20, right: 15),
              alignment: Alignment.centerRight,
              /// 使用controller来获取数据
              child: TextWidget(controller.selectMemberStr),
            );
          })
        ],
      ),
    );
  }
}

6、跨页面交互

在A界面处理数据,需要再B界面显示的时候,或者C界面,在或者D界面。只要注入了控制器。在其他界面就能拿到A界面的数据。
A界面注入
final _settingC = Get.put(ProjectCloudSettingController());
此刻A界面跳到B
Get.to(BPage);
B在跳到C
Get.to(CPage);
C在跳到D
Get.to(DPage);

D页面需要A界面的数据 注:这边要保证A一直在栈中。 
直接 Get.find(); 就可以拿到数据。比一级一级传值简单方便舒适吧。
final ProjectCloudSettingController settingC = Get.find();

7、黑暗模式
可以参考前期写的博客。黑暗模式的适配

以上是关于Flutter状态管理--GetX的简单使用的主要内容,如果未能解决你的问题,请参考以下文章

Flutter状态管理--GetX的简单使用

Flutter状态管理--GetX的简单使用

Flutter GetX 状态管理不起作用

Flutter 响应式状态管理框架GetX

Flutter 响应式状态管理框架GetX

Flutter状态管理终极方案GetX第一篇——路由