Flutter web - 根据 url 设置状态

Flutter web - Set state based on url

我正在开发一个 flutter 网站,顶部有一个持久导航栏,显示用户所在的当前页面,方法是在活动页面的标题周围添加边框,如下所示。

我在网站上使用 url 导航,因此用户可以使用特定的 url:

访问不同的页面

由于用户可以直接访问网站页面,因此我需要根据url设置页面加载时导航栏的状态。但是我无法在构建期间调用 setState 并且出现以下错误:

Another exception was thrown: setState() or markNeedsBuild() called during build.

我正在使用 Navigators 和 Routes 进行 url 导航,如下所示:

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: Strings.appName,
      theme: ThemeData(
        primarySwatch: Colors.cyan,
      ),
      builder: (context, child) => Dashboard(child: child!),
      navigatorKey: locator<NavigationService>().navigatorKey,
      onGenerateRoute: generateRoute,
      initialRoute: Routes.aboutRoute,
    );
  }
}

我使用Provider来控制导航栏的状态如下:

class NavigationBarProvider extends ChangeNotifier {
  List<bool> isSelected = [false, false, false, false];
  List<bool> isHovering = [false, false, false, false];

  void setSelected(int _index) {
    isSelected = List.filled(4, false);

    isSelected[_index] = true;

    notifyListeners();
  }

  void setHovering(int _index, bool _val) {
    isHovering[_index] = _val;

    notifyListeners();
  }

  bool isSelHov(int _index) {
    return isSelected[_index] || isHovering[_index];
  }
}

这是我的导航栏按钮小部件:

return InkWell(
      onTap: () {
        locator<NavigationService>().navigateTo(routeName);

        provider.setSelected(index);
      },
      onHover: (value) {
        provider.setHovering(index, value);
      },
      child: SizedBox(
        width: 100.0,
        height: 50.0,
        child: Stack(
          children: [
            Center(
              child: AnimatedContainer(
                duration: const Duration(milliseconds: 500),
                curve: Curves.easeInCirc,
                width: provider.isSelHov(index) ? 100.0 : 0.0,
                height: provider.isSelHov(index) ? 50.0 : 0.0,
                decoration: BoxDecoration(
                  border: Border.all(
                    color: Colors.white,
                    width: provider.isSelHov(index) ? 0.0 : 10.0,
                  ),
                  borderRadius: BorderRadius.circular(provider.isSelHov(index) ? 10.0 : 50.0),
                ),
              ),
            ),
            Center(
              child: Text(
                name,
                style: const TextStyle(
                  fontSize: 16.0,
                  color: Colors.white,
                ),
              ),
            ),
          ],
        ),
      ),
    );

请帮助我了解如何设置状态,并在使用特定 url.

启动网站时显示活动导航按钮

感谢您提供的任何帮助。非常感谢。

编辑

这是我的导航栏代码,索引为:

ChangeNotifierProvider<NavigationBarProvider>(
            create: (context) => NavigationBarProvider(),
            child: Consumer<NavigationBarProvider>(
              builder: (context, provider, child) {
                return Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  crossAxisAlignment: CrossAxisAlignment.end,
                  children: [
                    NavBarButton(
                      index: 0,
                      name: 'About Me',
                      routeName: Routes.aboutRoute,
                      provider: provider,
                    ),
                    NavBarButton(
                      index: 1,
                      name: 'Projects',
                      routeName: Routes.projectsRoute,
                      provider: provider,
                    ),
                    NavBarButton(
                      index: 2,
                      name: 'Skills',
                      routeName: Routes.skillsRoute,
                      provider: provider,
                    ),
                    NavBarButton(
                      index: 3,
                      name: 'Contact Me',
                      routeName: Routes.contactsRoute,
                      provider: provider,
                    ),
                  ],
                );
              },
            ),
          )

编辑 2

我设法自己找到了解决方案,我在下面提供了它作为答案之一。谢谢。

我已经找到解决办法了。我在整个应用程序中实施了 Provider,并在生成路由时也更改了选定的值。以下是我的工作代码:

我的 runApp:

runApp(
    ChangeNotifierProvider<NavBarProvider>(
      create: (context) => NavBarProvider(),
      child: const MyApp(),
    ),
  );

我正在使用自定义 RouteRouteBuilder,如下所示:

_FadeRoute(
      {required this.index, required this.child, required this.routeName})
      : super(
          settings: RouteSettings(name: routeName),
          pageBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
          ) {
            Future.delayed(Duration.zero, () async {
              Provider.of<NavBarProvider>(context, listen: false).setSelected(index);
            });
            return child;
          },
          transitionsBuilder: (
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
            Widget child,
          ) {
            return FadeTransition(
              opacity: animation,
              child: child,
            );
          },
        );

其余代码是一样的,除了我在 NavBar Widget 中删除了 ChangeNotifierProvider 作为父级,并且只留下 Consumer 如下:

Consumer<NavigationBarProvider>(
          builder: (context, provider, child) {
            return Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              crossAxisAlignment: CrossAxisAlignment.end,
              children: [
                NavBarButton(
                  index: 0,
                  name: 'About Me',
                  routeName: Routes.aboutRoute,
                  provider: provider,
                ),
                NavBarButton(
                  index: 1,
                  name: 'Projects',
                  routeName: Routes.projectsRoute,
                  provider: provider,
                ),
                NavBarButton(
                  index: 2,
                  name: 'Skills',
                  routeName: Routes.skillsRoute,
                  provider: provider,
                ),
                NavBarButton(
                  index: 3,
                  name: 'Contact Me',
                  routeName: Routes.contactsRoute,
                  provider: provider,
                ),
              ],
            );
          },
        )