flutter - XXXController 未找到您需要调用 Get.put 或 Get.lazyPut

标签 flutter dart flutter-getx

我正在尝试使用下一个布局创建简单的应用程序:

enter image description here

按钮应该切换 Widget1\Widget2。

我写了下一个代码(复制粘贴准备就绪):

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get_core/src/get_main.dart';
import 'package:get/get.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      initialBinding: HomeBinding(),
      initialRoute: '/widget1',
      home: Scaffold(
          appBar: AppBar(
            title: Text("Demo"),
          ),
          body: SafeArea(
            child: IndexedStack(
              index: Get.find<NavigationBarController>().tabIndex.value,
              children: [
                Widget1(), 
                Widget2()
              ],
            ),
          ),
          bottomNavigationBar: BottomNavigationBar(
              currentIndex: Get.find<NavigationBarController>().tabIndex.value,
              onTap: Get.find<NavigationBarController>().changeTabIndex,
              items: [
                _bottomNavigationBarItem(
                  icon: CupertinoIcons.home,
                  label: 'Button1',
                ),
                _bottomNavigationBarItem(
                  icon: CupertinoIcons.rocket_fill,
                  label: 'Button2',
                ),
              ])),

      getPages: [
        GetPage(
          name: '/widget1',
          page: () => Widget1(),
          binding: Widget1_Bindings(),
        ),
        GetPage(
          name: '/widget2',
          page: () => Widget2(),
          binding: Widget2_Bindings(),
        ),
      ],
      debugShowCheckedModeBanner: false,
      themeMode: ThemeMode.system,
    );
  }
}

class NavigationBarController extends GetxController {
  static NavigationBarController get to => Get.find();
  var tabIndex = 0.obs;

  void changeTabIndex(int index) {
    tabIndex.value = index;
    update();
  }

  @override
  void onInit() {
    super.onInit();
  }

  @override
  void dispose() {
    super.dispose();
  }
}

class Controller1 extends GetxController {
  var _test2 = "test1".obs;
  get test1 => this._test2.value;
}

class Controller2 extends GetxController {
  var _test2 = "test2".obs;
  get test1 => this._test2.value;
}

class Widget1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text("Widget1"),
    );
  }
}


class HomeBinding extends Bindings {
  @override
  void dependencies() {
     Get.lazyPut(() => NavigationBarController());
  }
  
}

class Widget1_Bindings extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => Controller1());
  }
}

class Widget2_Bindings extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => Controller2());
  }
}

class Widget2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text("Widget2"),
    );
  }
}

_bottomNavigationBarItem({required IconData icon, required String label}) {
  return BottomNavigationBarItem(
    icon: Icon(icon),
    label: label,
  );
}

代码有两个问题。第一个是我收到错误: enter image description here

第二个是我无法弄清楚如何让 GetX 路由像:Get.to 工作。

最佳答案

这里有一些问题。

首先,您在 GetMaterialApp 中定义了一个 initialRoute 和一个 home,它们是两个不同的目的地。使用其中之一,而不是两者。

您将 NavigationBarController 绑定(bind)到您的 initialRoute 中定义的内容,但该应用试图转到您在home 属性。因此该绑定(bind)永远不会被调用,这就是 Controller 未找到错误的原因。

因为你的 NavigationBarController 基本上是全局需要的,而不是逐页需要,所以我会失去它的绑定(bind)并在运行前在 main 中初始化它应用程序。

void main() {
  Get.put(NavigationBarController());
  runApp(MyApp());
}

其次,如果您正在使用 GetX 类中的可观察变量,并且您希望 UI 发生变化,则需要将其包装在 ObxGetX 小部件。因此,将 BottomNavigationBar 包装在 Obx 中。

   bottomNavigationBar: Obx(
        () => BottomNavigationBar(
          currentIndex: Get.find<NavigationBarController>().tabIndex.value,
          onTap: Get.find<NavigationBarController>().changeTabIndex,
          items: [
            _bottomNavigationBarItem(
              icon: CupertinoIcons.home,
              label: 'Button1',
            ),
            _bottomNavigationBarItem(
              icon: CupertinoIcons.rocket_fill,
              label: 'Button2',
            ),
          ],
        ),
      ),

与您的 IndexedStack 相同。它需要包装在 Obx 中以根据 tabIndex 的更改重建。

Obx(
    () => IndexedStack(
    index: Get.find<NavigationBarController>().tabIndex.value,
    children: [Widget1(), Widget2()],
   ),
  ),

现在您的 BottomNavigationBar 可以工作了。至于 bindings,由于您的应用基于选项卡而不是导航到完整页面,因此您永远不必手动导航到带有 Get.to(() => Widget1( ));,这种情况下 Bindings 可以派上用场,但对于这种情况,我看不到使用它们有任何好处。我只会在每个选项卡中初始化 Controller 。所以总的来说它看起来像这样。我摆脱了 getPages 也是因为它们没有被使用。

void main() {
  Get.put(NavigationBarController());
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      home: HomePage(),
      debugShowCheckedModeBanner: false,
      themeMode: ThemeMode.system,
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Demo"),
      ),
      body: SafeArea(
        child: Obx(
          () => IndexedStack(
            index: Get.find<NavigationBarController>().tabIndex.value,
            children: [Widget1(), Widget2()],
          ),
        ),
      ),
      bottomNavigationBar: Obx(
        () => BottomNavigationBar(
          currentIndex: Get.find<NavigationBarController>().tabIndex.value,
          onTap: Get.find<NavigationBarController>().changeTabIndex,
          items: [
            _bottomNavigationBarItem(
              icon: CupertinoIcons.home,
              label: 'Button1',
            ),
            _bottomNavigationBarItem(
              icon: CupertinoIcons.rocket_fill,
              label: 'Button2',
            ),
          ],
        ),
      ),
    );
  }
}

class NavigationBarController extends GetxController {
  static NavigationBarController get to => Get.find();
  var tabIndex = 0.obs;

  final widgetList = <Widget>[Widget1(), Widget2()];

  void changeTabIndex(int index) {
    tabIndex.value = index;
  //  update(); don't need this, only if you're using GetBuilder
  }

  @override
  void onInit() {
    super.onInit();
  }

  @override
  void dispose() {
    super.dispose();
  }
}

class Controller1 extends GetxController {
  var _test2 = "test1".obs;
  get test1 => this._test2.value;
}

class Controller2 extends GetxController {
  var _test2 = "test2".obs;
  get test1 => this._test2.value;
}

class Widget1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final controller = Get.put(Controller1());
    return Center(
      child: Container(
        child: Obx(() => Text(controller.test1)),
      ),
    );
  }
}

class Widget2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final controller = Get.put(Controller2());
    return Center(
      child: Container(
        child: Obx(() => Text(controller.test1)),
      ),
    );
  }
}

_bottomNavigationBarItem({required IconData icon, required String label}) {
  return BottomNavigationBarItem(
    icon: Icon(icon),
    label: label,
  );
}

此外,如果是我,我会使用 GetBuilder 来处理所有事情而不是可观察的流,因为您没有做任何真正证明流合理的事情。它们都有效,但 GetBuilder 是性能最高的选项。

更新:

要在评论中回答您的问题:不,您不需要 IndexedStack

您可以在给定索引处传入小部件列表,当索引更改时 Obx 重建。关于 const 构造函数的说明与此无关,但您应该尽可能做。

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);
  final _widgetList = const <Widget>[
    Widget1(),
    Widget2()
  ]; // add const constructors to both these widgets

  @override
  Widget build(BuildContext context) {
    final controller = Get.find<NavigationBarController>();
    return Scaffold(
      appBar: AppBar(
        title: Text("Demo"),
      ),
      body: SafeArea(
        child: Obx(
          () => Center(
            child: _widgetList[controller.tabIndex.value], // or _widgetList.elementAt(controller.tabIndex.value)
          ),
        ),
      ),
...

关于flutter - XXXController 未找到您需要调用 Get.put 或 Get.lazyPut,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69104878/

相关文章:

flutter - 如何使用 getx statemanagment 在 flutter 中更新选定的单选按钮

dart - 在 Flutter 应用程序中更改 SliverAppBar 标题颜色

dart - 未处理的异常 : InternalLinkedHashMap<String, 动态 >' is not a subtype of type ' 列表<动态>

java - 如何在 Flutter/Dart 中从音频文件中获取字节数据(必须是有符号的 int/bytes),就像 AudioInputStream 在 java 中为您提供的那样

Dart 对象到 native - UnimplementedError : structured clone of other type

flutter - 如何使用 Getx 构建动画启动画面?

android - 我需要自定义切换按钮

Flutter 通过向右或向左滑动来管理 Offset 的 dx

flutter - 如果传递了渐变,则框装饰中的渐变或颜色

Flutter:表单验证同时验证所有文本字段