...Yolo... 2024-04-27 18:37 采纳率: 50%
浏览 5

flutter自定义按钮全局悬浮不生效,

flutter自定义按钮全局悬浮不生效,跳转新页面就会消失,我放在main部件下跳转新页面后也会消失,是为什么,在主页面的tab栏中相互切换则不会消失,页面结构和生命周期的变化Overlay 没有在全局范围内保持,自定义的可拖动按钮不全局显示,跳转新页就消失,使用的是get.to和off都一样会消失,甚至使用了flutter原生的navigate跳转也是会消失,我已经放在了marin.dart根部件了,Scaffold结构改变
-main.dart-

// 定义main函数作为应用的入口点
void main() async {
  // 确保Flutter的widget系统初始化完成
  WidgetsFlutterBinding.ensureInitialized();
  // 初始化GetStorage
  await GetStorage.init();
  // 初始化Service,使用Get.lazyPut()方法来延迟加载服务
  await Service.init();
  final isFirstTime = GetStorage().read('isFirstTime') ?? true;
  // 初始化MediaKit
  // MediaKit.ensureInitialized();
  // 设置设备的首选方向为纵向
  await SystemChrome.setPreferredOrientations(<DeviceOrientation>[
    DeviceOrientation.portraitUp,
    DeviceOrientation.portraitDown
  ]).then((_) => runApp(MyApp(
        isFirstTime: isFirstTime,
      )));
}

// 定义全局的导航键
// final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();


class MyApp extends StatelessWidget {
// 是否是第一次打开应用
  final bool isFirstTime;

  const MyApp({super.key, required this.isFirstTime});


  void _showSearchOverlay(BuildContext context) {
    final overlay = Overlay.of(context);
    late OverlayEntry overlayEntry;
    overlayEntry = OverlayEntry(
      builder: (context) => SearchOverlay(overlayEntry),
    );
    overlay.insert(overlayEntry);
  }

  //
  @override
  Widget build(BuildContext context) {
    // 设置状态栏样式
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
      // 设置状态栏颜色为透明
      statusBarColor: Colors.transparent,
      // 设置状态栏图标颜色为黑色
      statusBarIconBrightness: Brightness.dark,
      // 设置状态栏亮度为黑色
      statusBarBrightness:
          !kIsWeb && Platform.isAndroid ? Brightness.dark : Brightness.light,
      // 设置导航栏颜色为白色
      systemNavigationBarColor: Colors.white,
      // 设置导航栏分隔线颜色为透明
      systemNavigationBarDividerColor: Colors.transparent,
      // 设置导航栏图标颜色为黑色
      systemNavigationBarIconBrightness: Brightness.dark,
    ));

    return GetMaterialApp(
      title: 'English Hub',
      // 隐藏调试横幅
      debugShowCheckedModeBanner: false,
      // 设置应用的语言环境
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: [
        Locale('en'), // English
        Locale('zh'), // Chinese
      ],
      theme: ThemeData(
        textTheme: AppTheme.textTheme,
        // 设置应用的平台为android
        platform: TargetPlatform.android,
        // colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        // useMaterial3: true,
      ),

      // 不行
      // home: Scaffold(
      //   // bottomNavigationBar: const CustomBottomNavigationBar(),
      //   // 浮动按钮
      //   // floatingActionButton: DraggableFloatingButton(onTap: () => _showSearchOverlay(context)),
      //   body: Stack(
      //     children: [
      //       MyHomePage(),
      //       DraggableFloatingButton(onTap: () => _showSearchOverlay(context)),
      //     ]
      //   )
      // ),

      // 不行
      // home: Overlay(
      //   // Create an overlay
      //   initialEntries: [
      //     // Add entries to the overlay
      //     OverlayEntry(
      //       builder: (context) => const HomeNavigation(),
      //     ),
      //     OverlayEntry(
      //       // Add DraggableFloatingButton to the overlay
      //       builder: (context) => DraggableFloatingButton(
      //         onTap: () => _showSearchOverlay(context),
      //       ),
      //     ),
      //   ],
      // ),

      // home: Scaffold(
      //   // bottomNavigationBar: const CustomBottomNavigationBar(),
      //   body: Stack(
      //     children: [
      //       const HomeNavigation(),
      //       // DraggableFloatingButton placed outside of the main content stack
      //       DraggableFloatingButton(onTap: () => _showSearchOverlay(context)),
      //     ],
      //   ),
      // ),

      home: Scaffold(
        body: Overlay(
          initialEntries: [
            OverlayEntry(
              builder: (context) => const HomeNavigation(), // 主页面
            ),
            OverlayEntry(
              builder: (context) => DraggableFloatingButton(onTap: () => _showSearchOverlay(context)), // 浮动按钮
            ),
          ],
        ),
      ),

      // 根据 isFirstTime 判断初始路由
      initialRoute: isFirstTime ? Routes.introduction : Routes.homeNavigation,
      // 路由表
      getPages: Routes.routes,
      // key: navigatorKey, // 设置GlobalKey
    );
  }
}

home_navigation.dart

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

  @override
  // ignore: library_private_types_in_public_api
  _HomeNavigationState createState() => _HomeNavigationState();
}

class _HomeNavigationState extends State<HomeNavigation> {
  Widget? screenView;
  // 当前显示的页面
  DrawerIndex? drawerIndex;
  // 当前选中的抽屉菜单项


  @override
  void initState() {
    // 初始化为首页home
    // drawerIndex = DrawerIndex.HOME;
    screenView = MyHomePage();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: AppTheme.white,
      child: SafeArea(
        // 是否受屏幕UI影响
        top: false,
        bottom: false,
        child: Scaffold(
          backgroundColor: AppTheme.nearlyWhite,
          body: HomeDrawerController(
            screenIndex: drawerIndex,
            // 抽屉宽度设置为屏幕宽度的0.75
            drawerWidth: MediaQuery.of(context).size.width * 0.75,
            onDrawerCall: (DrawerIndex drawerIndexdata) {
              changeIndex(drawerIndexdata);
              // 从抽屉菜单中回调,根据传递的DrawerIndex枚举索引替换屏幕视图
            },
            // 替换屏幕视图
            screenView: screenView,
          ),
          // 底部导航栏
          // bottomNavigationBar: const CustomBottomNavigationBar(),
        ),
      ),
    );
  }

MyhomePage.dart


class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  // 控制器
  final NavigationController _navigationController = Get.find<NavigationController>();
  final WordsController _wordsController = Get.find<WordsController>();

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

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

  Future<bool> getData() async {
    await Future<dynamic>.delayed(const Duration(milliseconds: 0));
    return true;
  }

  void _showSearchOverlay(BuildContext context) {
    final overlay = Overlay.of(context);
    late OverlayEntry overlayEntry;
    overlayEntry = OverlayEntry(
      builder: (context) => SearchOverlay(overlayEntry),
    );
    overlay.insert(overlayEntry);  // 弹出搜索框
  }

  @override
  Widget build(BuildContext context) {
    var brightness = MediaQuery.of(context).platformBrightness;
    bool isLightMode = brightness == Brightness.light;
    return Scaffold(
      backgroundColor:
          isLightMode == true ? AppTheme.white : AppTheme.nearlyBlack,
      body: Stack( // 使用Stack组件来包含可拖动按钮
        children: [
          Padding(
            padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                appBar(), // 顶部AppBar

                Expanded( // 主体部分
                  child: FutureBuilder<bool>(
                    future: getData(),
                    builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
                      if (!snapshot.hasData) {
                        return const SizedBox();
                      } else {
                        return TabBarView(
                          controller: _navigationController.tabController,
                          children: [
                            GridViewPage(), // 首页
                            ListeningPage(), // 听力
                            ReadingPage(), // 阅读
                            SpokenPage(), // 口语
                          ],
                        );
                      }
                    },
                  ),
                ),
              ],
            ),
          ),
          // 浮动按钮
          // DraggableFloatingButton(onTap: () => _showSearchOverlay(context)),
        ],
      ),
//      底部导航栏
      bottomNavigationBar: const CustomBottomNavigationBar(),
      // 浮动按钮
    );
  }

  Widget appBar() {
    return SizedBox(
      // 顶部AppBar高度,
      height: AppBar().preferredSize.height,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.only(top: 8, left: 8),
            child: Container(
              width: AppBar().preferredSize.height - 8,
              height: AppBar().preferredSize.height - 8,
            ),
          ),
          Expanded(
            child: TabBar(
              controller: _navigationController.tabController,
              tabs: const [
                Tab(text: "首页"),
                Tab(text: "听力"),
                Tab(text: "阅读"),
                Tab(text: "口语"),
              ],
            ),
          ),
          IconButton(
            icon: const Icon(Icons.search),
            onPressed: () {
              // 跳转到搜索页面
            },
          ),
        ],
      ),
    );
  }
}
  • 写回答

3条回答 默认 最新

  • 阿里嘎多学长 2024-04-27 18:37
    关注

    以下内容由CHATGPT及阿里嘎多学长共同生成、有用望采纳:


    【问题概括】:这个问题的目的是解决Flutter中自定义按钮在全局悬浮时,跳转到新页面会消失的问题。

    【问题出现原因】:根据提供的信息,问题可能出现的原因有:

    1. 悬浮按钮被放置在了Overlay中,而Overlay是和它所在的BuildContext关联的。当跳转到新页面时,旧的BuildContext被销毁,导致OverlayEntry也随之销毁,因此悬浮按钮消失。
    2. 使用Get.toGet.off或原生的Navigator跳转时,如果没有正确地管理全局Overlay,也会导致悬浮按钮消失。

    【问题解决方案】:为了使自定义按钮全局悬浮并且不随页面跳转而消失,可以采取以下步骤:

    1. OverlayEntry放置在全局的BuildContext中,如MaterialApp的根上下文中。
    2. 使用GlobalKey来保持对OverlayEntry的引用,以便在需要时可以更新或重新插入。
    3. 在跳转新页面时,确保全局OverlayEntry不会被销毁。

    【提供代码】:以下是修改后的main.dart中的相关代码:

    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await GetStorage.init();
      await Service.init();
      final isFirstTime = GetStorage().read('isFirstTime') ?? true;
      runApp(MyApp(
        isFirstTime: isFirstTime,
        floatingButtonKey: GlobalKey<OverlayEntry>(),
      ));
    }
    
    class MyApp extends StatelessWidget {
      final bool isFirstTime;
      final GlobalKey<OverlayEntry> floatingButtonKey;
    
      const MyApp({super.key, required this.isFirstTime, required this.floatingButtonKey});
    
      @override
      Widget build(BuildContext context) {
        // ... 省略其他代码 ...
    
        return GetMaterialApp(
          // ... 省略其他代码 ...
    
          home: Scaffold(
            body: Overlay(
              initialEntries: [
                OverlayEntry(
                  builder: (context) => const HomeNavigation(),
                ),
                // 使用GlobalKey来管理悬浮按钮的OverlayEntry
                floatingButtonKey.currentContext!,
              ],
            ),
            appBar: AppBar(
              title: Text('English Hub'),
            ),
          ),
          // ... 省略其他代码 ...
        );
      }
    }
    
    class DraggableFloatingButton extends StatelessWidget {
      final VoidCallback onTap;
    
      const DraggableFloatingButton({super.key, required this.onTap});
    
      @override
      Widget build(BuildContext context) {
        // 创建一个OverlayEntry并用GlobalKey引用
        final entry = OverlayEntry(
          builder: (context) => Positioned(
            bottom: 80,
            right: 20,
            child: FloatingActionButton(
              onPressed: onTap,
              child: Icon(Icons.add),
            ),
          ),
        );
        // 在构造函数中注册OverlayEntry
        final GlobalKey<OverlayEntry> key = GlobalKey();
        WidgetsBinding.instance!.addPostFrameCallback((_) {
          key.currentState = entry;
        });
    
        return Container(); // 这里不需要返回任何内容,因为我们在OverlayEntry中构建了悬浮按钮
      }
    }
    

    【代码运行方式】:将上述代码替换到你的项目中,确保Flutter环境已经搭建好,然后在终端中运行flutter run来启动应用。

    【代码预期运行结果】:悬浮按钮应该能够全局显示,并且在跳转到新页面时不会消失。

    【推荐相关链接】:

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 4月27日

悬赏问题

  • ¥15 前端echarts坐标轴问题
  • ¥15 CMFCPropertyPage
  • ¥15 ad5933的I2C
  • ¥15 请问RTX4060的笔记本电脑可以训练yolov5模型吗?
  • ¥15 数学建模求思路及代码
  • ¥50 silvaco GaN HEMT有栅极场板的击穿电压仿真问题
  • ¥15 谁会P4语言啊,我想请教一下
  • ¥15 这个怎么改成直流激励源给加热电阻提供5a电流呀
  • ¥50 求解vmware的网络模式问题 别拿AI回答
  • ¥24 EFS加密后,在同一台电脑解密出错,证书界面找不到对应指纹的证书,未备份证书,求在原电脑解密的方法,可行即采纳