【问题标题】:XXXController not found you need to call Get.put or Get.lazyPut找不到 XXXController 需要调用 Get.put 或 Get.lazyPut
【发布时间】:2021-11-05 08:01:26
【问题描述】:

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

按钮应该切换 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,
  );
}

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

第二个是我不知道如何获取 GetX 路由,例如:Get.to 工作。

【问题讨论】:

    标签: flutter dart flutter-getx


    【解决方案1】:

    这里有一些问题。

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

    您将 NavigationBarController 绑定到您在 initialRoute 中定义的内容,但应用程序试图转到您在 home 属性中的 Scaffold。这样绑定就永远不会被调用,这就是找不到控制器错误的原因。

    由于您的NavigationBarController 基本上是全局需要的,而不是逐页需要,所以我会失去它的绑定,并在运行应用程序之前将其初始化为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(() =&gt; Widget1()); 的页面,这种情况是Bindings 可以派上用场,但对于在这种情况下,我认为使用它们没有任何好处。我只会在每个选项卡中初始化控制器。所以总的来说它看起来像这样。我删除了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)
              ),
            ),
          ),
    ...
    

    【讨论】:

    • 非常感谢您的回答!你还能说bindings 什么时候有用吗?当我使用单独的屏幕\页面时?
    • 是的,虽然不是必需的,但在使用常规导航到不同屏幕时会很方便。
    【解决方案2】:

    原因 : Get.find() 在 Get.put(Controller) 之前被调用。 在初始化 Get.put() 之前调用 Get.find() 显示错误

    解决方案:您只需将 Get.put(controller) 调用到您的主类中,如下所示。那么任何类的 Get.find() 都会得到它。

    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatefulWidget {
    
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      final YourController controller = Get.put(YourController());
      ...
      
      @override
      Widget build(BuildContext context) {
      
        return MaterialApp(
        ......
      
    }
    

    注意:虽然有很多方法可以解决它。

    【讨论】:

      猜你喜欢
      • 2021-12-27
      • 2022-12-16
      • 2022-11-21
      • 2021-02-26
      • 2021-09-28
      • 2017-09-04
      • 2019-05-05
      • 1970-01-01
      • 2017-02-26
      相关资源
      最近更新 更多