Flutter Bloc:如何为底部条屏幕和普通屏幕提供一个cubit的实例?

发布于 2025-02-09 00:40:23 字数 2269 浏览 2 评论 0原文

我的应用中有一个导航底栏。 我创建了一个自定义类,用于路由,该类设置所有逻辑,用于导航到应用程序中的所有屏幕,但是底部的bar页面不在此自定义类中。 我有一个问题,为底栏的屏幕提供一个cubit的实例,在自定义类中提供了一个屏幕。 有建议吗?

class UserNavScreen extends StatefulWidget {
  static const routeName = 'homepage_screen';

  UserNavScreen();

  @override
  State<UserNavScreen> createState() => _UserNavScreenState();
}

class _UserNavScreenState extends State<UserNavScreen> {
  var _index = 2;

  final _userPages = [
    const UserProfileScreen(),
    const UserNotificationScreen(),
    BlocProvider<MapCubit>(
        create: (context) => MapCubit(
              mapRepositery: MapRepositery(
                mapProvider: MapProvider(),
              ),
              storesRepositery: StoresRepositery(
                storesProvider: StoresProvider(),
              ),
            )..getStoresLocation(),
        child: UserMapScreen()),
    const UserTopTenScreen(),
    const UserHomepageScreen()
  ];

 

  Widget build(BuildContext context) {
    return Scaffold(
      body: _userPages[_index],
      bottomNavigationBar: _buildNavUser(),
    );
  }

  Widget _buildNavUser() {
    return StyleProvider(
      style: StyleNavBottomBar(),
      child: ConvexAppBar(
        style: TabStyle.fixedCircle,
        backgroundColor: Colors.white,
        color: Colors.grey,
        initialActiveIndex: _index,
        activeColor: Colors.green,
        cornerRadius: 16,
        curveSize: 90,
        height: 60,
        onTap: (index) {
          setState(() {
            _index = index;
          });
        },
        elevation: 2,
        items: const [
          TabItem(
            icon: Icons.person,
          ),
          TabItem(
            icon: Icons.notifications,
          ),
          TabItem(icon: Icons.navigation),
          TabItem(
            icon: FontAwesomeIcons.medal,
          ),
          TabItem(
            icon: Icons.home,
          ),
        ],
      ),
    );
  }
}


class AppRoute {
  
  Route? onGenerateRoute(RouteSettings routeSettings) {
    switch (routeSettings.name) {
 case StoreMap.routeName:
        final args = routeSettings.arguments as Store;
        return MaterialPageRoute(
          builder: (context) => StoreMap(store: args),
        );
    }
  }
}

I have a navigation bottom bar in my app.
I created a custom class for routing that sets up all the logic for navigating to all the screens in the app, but the bottom bar pages are not in this custom class.
I have a problem providing a single instance of a cubit for a bottom bar's screen and a screen in the custom class.
Are there any suggestions?

class UserNavScreen extends StatefulWidget {
  static const routeName = 'homepage_screen';

  UserNavScreen();

  @override
  State<UserNavScreen> createState() => _UserNavScreenState();
}

class _UserNavScreenState extends State<UserNavScreen> {
  var _index = 2;

  final _userPages = [
    const UserProfileScreen(),
    const UserNotificationScreen(),
    BlocProvider<MapCubit>(
        create: (context) => MapCubit(
              mapRepositery: MapRepositery(
                mapProvider: MapProvider(),
              ),
              storesRepositery: StoresRepositery(
                storesProvider: StoresProvider(),
              ),
            )..getStoresLocation(),
        child: UserMapScreen()),
    const UserTopTenScreen(),
    const UserHomepageScreen()
  ];

 

  Widget build(BuildContext context) {
    return Scaffold(
      body: _userPages[_index],
      bottomNavigationBar: _buildNavUser(),
    );
  }

  Widget _buildNavUser() {
    return StyleProvider(
      style: StyleNavBottomBar(),
      child: ConvexAppBar(
        style: TabStyle.fixedCircle,
        backgroundColor: Colors.white,
        color: Colors.grey,
        initialActiveIndex: _index,
        activeColor: Colors.green,
        cornerRadius: 16,
        curveSize: 90,
        height: 60,
        onTap: (index) {
          setState(() {
            _index = index;
          });
        },
        elevation: 2,
        items: const [
          TabItem(
            icon: Icons.person,
          ),
          TabItem(
            icon: Icons.notifications,
          ),
          TabItem(icon: Icons.navigation),
          TabItem(
            icon: FontAwesomeIcons.medal,
          ),
          TabItem(
            icon: Icons.home,
          ),
        ],
      ),
    );
  }
}


class AppRoute {
  
  Route? onGenerateRoute(RouteSettings routeSettings) {
    switch (routeSettings.name) {
 case StoreMap.routeName:
        final args = routeSettings.arguments as Store;
        return MaterialPageRoute(
          builder: (context) => StoreMap(store: args),
        );
    }
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小忆控 2025-02-16 00:40:23

看来我们几乎具有相同的导航设置,我经历的是懒惰地实例化路由类内的肘,然后使用 blocprovider.value.value 将其提供给命名路线,之后提供路由全球使用 repositoryProvider 如下:

class AppRoute {
  //* This will only get instantiated when used
  late final MapCubit mapCubit = MapCubit(MapRepository(
      mapProvider: MapProvider(), storesProvider: StoresProvider()));

  Route? onGenerateRoute(RouteSettings routeSettings) {
    switch (routeSettings.name) {
      case StoreMap.routeName:
        final args = routeSettings.arguments as Store;
        return MaterialPageRoute(
          builder: (context) => BlocProvider.value(
            value: mapCubit,
            child: StoreMap(store: args),
          ),
        );
    }
  }

  void dispose() {
    mapCubit.close();
  }
}

现在在 main.dart

void main() {
  runApp(
    App(),
  );
}

class App extends StatefulWidget {
  App({Key? key}) : super(key: key);

  @override
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  @override
  void dispose() {
    context.read<AppRoute>().dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return RepositoryProvider(
      create: (context) => AppRoute(),
      child: MaterialApp(
        // some traditional code & boilerplate....
        onGenerateRoute: context.read<AppRoute>().onGenerateRoute,
      ),
    );
  }
}

,我们可以在任何地方访问cubit,尤其是从 usernavscreen ,我们可以在其中进一步提供它到所需的页面:

class UserNavScreen extends StatefulWidget {
  static const routeName = 'homepage_screen';

  const UserNavScreen({Key? key}) : super(key: key);

  @override
  State<UserNavScreen> createState() => _UserNavScreenState();
}

class _UserNavScreenState extends State<UserNavScreen> {
  var _index = 2;
  late final AppRoute _appRoute;
  late final List<Widget> _userPages;

  @override
  void initState() {
    _appRoute = context.read<AppRoute>();
    _userPages = [
      const UserProfileScreen(),
      const UserNotificationScreen(),
      //* Here we're accessing the same cubit instance that named routes will access.
      BlocProvider<MapCubit>.value(
        value: _appRoute.mapCubit..getStoresLocation(),
        child: const UserMapScreen(),
      ),
      const UserTopTenScreen(),
      const UserHomepageScreen(),
    ];
    super.initState();
  }

  Widget build(BuildContext context) {
    return Scaffold(
      body: _userPages[_index],
      bottomNavigationBar: _buildNavUser(),
    );
  }

  Widget _buildNavUser() {
    return StyleProvider(
      style: StyleNavBottomBar(),
      child: ConvexAppBar(
        style: TabStyle.fixedCircle,
        backgroundColor: Colors.white,
        color: Colors.grey,
        initialActiveIndex: _index,
        activeColor: Colors.green,
        cornerRadius: 16,
        curveSize: 90,
        height: 60,
        onTap: (index) {
          setState(() {
            _index = index;
          });
        },
        elevation: 2,
        items: const [
          TabItem(
            icon: Icons.person,
          ),
          TabItem(
            icon: Icons.notifications,
          ),
          TabItem(icon: Icons.navigation),
          TabItem(
            icon: FontAwesomeIcons.medal,
          ),
          TabItem(
            icon: Icons.home,
          ),
        ],
      ),
    );
  }
}

PS:请注意批准类中的处置方法(我更喜欢将其称为Applouter btw),此方法是在我们确定将永远不会再使用的情况下处置Cubit,在我们的情况下,它是获得的。首先实例化(在usernavscreen内部),这是因为我们有责任关闭由 blocprovider.value.value 提供的cub/bloc。

It seems we have almost identical navigation setup, what I've gone through was to lazily instantiate the cubit inside the routing class, then supply it to the named route using BlocProvider.value, after that provide the routing class globally using RepositoryProvider as follows:

class AppRoute {
  //* This will only get instantiated when used
  late final MapCubit mapCubit = MapCubit(MapRepository(
      mapProvider: MapProvider(), storesProvider: StoresProvider()));

  Route? onGenerateRoute(RouteSettings routeSettings) {
    switch (routeSettings.name) {
      case StoreMap.routeName:
        final args = routeSettings.arguments as Store;
        return MaterialPageRoute(
          builder: (context) => BlocProvider.value(
            value: mapCubit,
            child: StoreMap(store: args),
          ),
        );
    }
  }

  void dispose() {
    mapCubit.close();
  }
}

Now in main.dart

void main() {
  runApp(
    App(),
  );
}

class App extends StatefulWidget {
  App({Key? key}) : super(key: key);

  @override
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  @override
  void dispose() {
    context.read<AppRoute>().dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return RepositoryProvider(
      create: (context) => AppRoute(),
      child: MaterialApp(
        // some traditional code & boilerplate....
        onGenerateRoute: context.read<AppRoute>().onGenerateRoute,
      ),
    );
  }
}

Now we can access the cubit anywhere, and specifically from UserNavScreen where we provide it further to the required page:

class UserNavScreen extends StatefulWidget {
  static const routeName = 'homepage_screen';

  const UserNavScreen({Key? key}) : super(key: key);

  @override
  State<UserNavScreen> createState() => _UserNavScreenState();
}

class _UserNavScreenState extends State<UserNavScreen> {
  var _index = 2;
  late final AppRoute _appRoute;
  late final List<Widget> _userPages;

  @override
  void initState() {
    _appRoute = context.read<AppRoute>();
    _userPages = [
      const UserProfileScreen(),
      const UserNotificationScreen(),
      //* Here we're accessing the same cubit instance that named routes will access.
      BlocProvider<MapCubit>.value(
        value: _appRoute.mapCubit..getStoresLocation(),
        child: const UserMapScreen(),
      ),
      const UserTopTenScreen(),
      const UserHomepageScreen(),
    ];
    super.initState();
  }

  Widget build(BuildContext context) {
    return Scaffold(
      body: _userPages[_index],
      bottomNavigationBar: _buildNavUser(),
    );
  }

  Widget _buildNavUser() {
    return StyleProvider(
      style: StyleNavBottomBar(),
      child: ConvexAppBar(
        style: TabStyle.fixedCircle,
        backgroundColor: Colors.white,
        color: Colors.grey,
        initialActiveIndex: _index,
        activeColor: Colors.green,
        cornerRadius: 16,
        curveSize: 90,
        height: 60,
        onTap: (index) {
          setState(() {
            _index = index;
          });
        },
        elevation: 2,
        items: const [
          TabItem(
            icon: Icons.person,
          ),
          TabItem(
            icon: Icons.notifications,
          ),
          TabItem(icon: Icons.navigation),
          TabItem(
            icon: FontAwesomeIcons.medal,
          ),
          TabItem(
            icon: Icons.home,
          ),
        ],
      ),
    );
  }
}

PS: Notice the dispose method inside the AppRoute class (I prefer calling it AppRouter btw), this method is to dispose the cubit when we're sure it will never be used again, in our case it's where it got first instantiated (inside UserNavScreen), and that is because it's our responsibility to close a cubit/bloc that was provided by BlocProvider.value .

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文