Flutter web - 根据 url 设置状态
Flutter web - Set state based on url
我正在开发一个 flutter 网站,顶部有一个持久导航栏,显示用户所在的当前页面,方法是在活动页面的标题周围添加边框,如下所示。
我在网站上使用 url 导航,因此用户可以使用特定的 url:
访问不同的页面
- webpage.com/#/about : 打开'About Me'页面
- webpage.com/#/skills : 打开'Skills'页面等等
由于用户可以直接访问网站页面,因此我需要根据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,
),
],
);
},
)
我正在开发一个 flutter 网站,顶部有一个持久导航栏,显示用户所在的当前页面,方法是在活动页面的标题周围添加边框,如下所示。
我在网站上使用 url 导航,因此用户可以使用特定的 url:
访问不同的页面- webpage.com/#/about : 打开'About Me'页面
- webpage.com/#/skills : 打开'Skills'页面等等
由于用户可以直接访问网站页面,因此我需要根据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,
),
],
);
},
)