You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用GetX状态管理:首屏Controller变量显示空白,后续页面正常

首屏GetX Controller变量空白问题排查与解决

问题现象

  • 首屏调用GetX Controller中的屏幕宽高变量时,变量显示无效(空白/0值)
  • 通过GetX路由跳转到后续页面后,Controller的变量能正常工作
  • 用MediaQuery直接获取宽高时首屏显示正常,仅通过Controller获取时出问题
  • 已确认Controller状态更新正常、数据可用

核心代码

主入口代码

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

class MyApp extends StatelessWidget {
   const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return Listener(
      onPointerHover: (onPointerMove){
        FocusManager.instance.primaryFocus?.unfocus();
      },
      child: GetMaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'Flutter Demo',
        getPages: AppRoutes.appRoutes(),
        initialBinding: InitialBindings(),
        initialRoute: RoutesName.launchScreen,
      ),
    );
  }
}

首屏LaunchScreen代码

class LaunchScreen extends StatefulWidget {
  const LaunchScreen({super.key});

  @override
  State<LaunchScreen> createState() => _LaunchScreenState();
}
class _LaunchScreenState extends State<LaunchScreen> {
  final controller = Get.put(LaunchController());
  final AppThemeState _appTheme = AppThemeState();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 25),
        height: controller.height,
        width: controller.width,
        decoration: const BoxDecoration(
          image: DecorationImage(
              image: AssetImage(ImageAssetsPath.launchBackImage),
              fit: BoxFit.fill),
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            Text("Dhulayi.com".tr,
                style: _appTheme.customTextStyle(
                    fontSize: 35, fontWeightType: _appTheme.boldWeightType)),
            SizedBox(
              height: controller.height * 0.02,
            ),
            Text(
              "lorem Ipsum is simply dummy text of the printing and typesetting industry.LoremIpsum has been the industry's standard dummy text ever since the 1500s",
              style: _appTheme.customTextStyle(
                  fontSize: 12, fontWeightType: _appTheme.regularWeightType),
              textAlign: TextAlign.center,
            ),
            SizedBox(
              height: controller.height * .05,
            ),
            MaterialButton(
              onPressed: () {
                controller.navigateToMain();
              },
              height: 50,
              color: AppColors.redBackGroundColor,
              minWidth: controller.width,
              child: Text("Swipe Here",
                  style: _appTheme.customTextStyle(
                      color: AppColors.buttonTextColor,
                      fontWeightType: _appTheme.boldWeightType,
                      fontSize: 20)),
            )
          ],
        ),
      ),
    );
  }
}

LaunchController代码

class LaunchController extends GetxController{
      double height = Get.height;
      double width = Get.width;

      void navigateToMain(){
        Get.offNamed(RoutesName.verifyView);
      }
    }

问题原因

Controller初始化时机过早:在GetMaterialApp尚未完成上下文注入时,就直接在Controller的成员变量中赋值Get.height/Get.width,此时GetX还未获取到正确的屏幕上下文信息,导致宽高变量为0或无效值。

  • 首屏的Controller是在State的成员变量中直接Get.put()初始化的,这个时机早于GetMaterialApp完成上下文初始化的时机
  • 后续页面通过GetX路由跳转时,GetMaterialApp已经完成初始化,上下文信息正常,所以Get.height/Get.width能正确获取

解决方案

方案1:在Controller的onInit生命周期中初始化宽高

将宽高的赋值移到onInit方法中,该方法会在Controller绑定到GetX上下文后执行:

class LaunchController extends GetxController{
  late double height;
  late double width;

  @override
  void onInit() {
    super.onInit();
    height = Get.height;
    width = Get.width;
  }

  void navigateToMain(){
    Get.offNamed(RoutesName.verifyView);
  }
}

方案2:通过InitialBindings提前绑定Controller,在build中获取

  1. 在InitialBindings中提前绑定Controller:
class InitialBindings extends Bindings {
  @override
  void dependencies() {
    Get.put(LaunchController());
  }
}
  1. 在首屏的build方法中用Get.find()获取Controller:
class _LaunchScreenState extends State<LaunchScreen> {
  late LaunchController controller;
  final AppThemeState _appTheme = AppThemeState();
  
  @override
  Widget build(BuildContext context) {
    controller = Get.find<LaunchController>();
    return Scaffold(
      // ... 原有UI代码
    );
  }
}

方案3:使用响应式变量(Obx)自动更新

将宽高改为响应式变量,确保上下文就绪后自动更新UI:

  1. 修改Controller:
class LaunchController extends GetxController{
  final RxDouble height = 0.0.obs;
  final RxDouble width = 0.0.obs;

  @override
  void onInit() {
    super.onInit();
    height.value = Get.height;
    width.value = Get.width;
  }

  void navigateToMain(){
    Get.offNamed(RoutesName.verifyView);
  }
}
  1. 在UI中用Obx包裹使用变量的组件:
Obx(() => Container(
  padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 25),
  height: controller.height.value,
  width: controller.width.value,
  decoration: const BoxDecoration(
    image: DecorationImage(
        image: AssetImage(ImageAssetsPath.launchBackImage),
        fit: BoxFit.fill),
  ),
  child: Column(
    // ... 原有子组件
  ),
))

额外注意事项

  • 首屏的Controller推荐通过InitialBindings提前绑定,避免在页面中直接Get.put()导致初始化时机问题
  • 不要在Controller的成员变量初始化阶段直接调用Get.height/Get.width或其他依赖GetX上下文的方法,这类操作应放在onInit或onReady生命周期中

内容的提问来源于stack exchange,提问作者Pratham Patel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 07:10:56