XXXController未找到,您需要调用Get.put或Get.lazyPut。

3

我正在尝试创建一个如下图所示的简单应用程序:

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一样工作。

3个回答

2
你这里有几个问题。
首先,你在GetMaterialApp中定义了initialRoutehome,它们是两个不同的目的地。只使用其中之一而不是两个。
其次,你将NavigationBarControllerinitialRoute中定义的内容绑定,但是应用程序试图进入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(() => 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而不是observable streams,因为你没有做任何真正需要流的事情。两者都可以使用,但GetBuilder是最高效的选项。

更新:

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

您可以在给定索引处传递一组小部件,当索引更改时,Obx将重新构建。有关常量构造函数的注意事项与此无关,但这是您应该尽可能做的事情。

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何时有用?当我使用单独的屏幕/页面时? - Dmitry Bubnenkov
是的,虽然不是必需的,但在使用常规导航到不同屏幕时它们可能很方便。 - Loren.A
我在主函数中使用了Get.put(),但页面没有加载,在终端中显示flutter: Null check operator used on a null value,但我没有使用null check operator(!)...(我的问题与BottomNabBar有关)。 - saddam

0

原因:当在初始化Get.put(Controller)之前调用Get.find()时,就会发生这种情况。在初始化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(
    ......
  
}

注意:虽然有很多解决方案。

0

我的问题是

Get.to(() => const OurDonorView()) 

相反地

Get.toNamed('/profile');

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接