Flutter 持久侧边栏
Flutter persistent sidebar
在我的应用程序中,我希望有一个侧边栏,允许我在我的应用程序的任何地方访问特定功能。
我想要什么:
- 当我推送我的页面时侧边栏仍然可见
- 我可以使用侧边栏功能之一推送命名路线或打开模式
- 我无法在某些页面上显示边栏
我是做什么的:
红色是执着sidebar
,黄色是我的app content
。
如果我在 HomeView
中单击我的 profil button
,则会显示 ProfilView
并且我的侧边栏仍然可见,所以没关系
我的AppView
:
class AppView extends StatelessWidget {
const AppView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: AppConfig.kAppName,
debugShowCheckedModeBanner: false,
theme: AppTheme().data,
builder: (context, child) => SidebarTemplate(child: child), // => I create a template
onGenerateRoute: RouterClass.generate,
initialRoute: RouterName.kHome,
);
}
我的SidebarTemplate
:(显示侧边栏并使用我的路由器加载页面)
class SidebarTemplate extends StatelessWidget {
final Widget? child;
const SidebarTemplate({Key? key, this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body : Row(
children: [
SidebarAtom(), // => My sidebar Widget
Expanded(
child: ClipRect(
child: child! // => My view
),
)
],
)
),
);
}
}
我的 RouterClass
:
abstract class RouterClass{
static Route<dynamic> generate(RouteSettings settings){
final args = settings.arguments;
switch(settings.name){
case RouterName.kHome:
return MaterialPageRoute(
builder: (context) => HomeView()
);
case RouterName.kProfil:
return MaterialPageRoute(
builder: (context) => ProfilView(title: "Profil",)
);
default:
return MaterialPageRoute(
builder: (context) => Error404View(title: "Erreur")
);
}
}
}
怎么做:
- 因为我有一个错误,所以要从我的边栏中使用按钮 pushNamed 或打开模式
The following assertion was thrown while handling a gesture:
I/flutter (28519): Navigator operation requested with a context that does not include a Navigator.
I/flutter (28519): The context used to push or pop routes from the Navigator must be that of a widget that is a
I/flutter (28519): descendant of a Navigator widget.
- 在我想要的时候隐藏边栏,例如
SplashScreen
任何有关实现此目标的最佳方法的指导将不胜感激。
正如您从 Profil
屏幕截图中看到的那样,边栏不是 Navigator
的小部件子树的一部分(后退按钮仅在配置文件小部件上)。这意味着您无法从侧边栏的 context
中找到 Navigator
。发生这种情况是因为您在 MaterialApp
中使用了 builder
,其中 inserts widgets above the navigator.
这也是为什么当你想显示启动画面时不能隐藏侧边栏的原因。
您真的需要在 MaterialApp
上使用 builder
吗?然后您可以全局保存导航器并从侧边栏访问它。 This is the first article when I search on DuckDuckGo,你可以关注。
要显示 SplashScreen,您需要向 AppView
添加状态并更改 builder
函数。如果你问我不是很好
我建议您重新考虑您的体系结构并删除 MaterialApp
中的 builder
。
你可以用一个NavigatorObserver
来监听路由的变化
class MyNavObserver with NavigatorObserver {
final StreamController<int> streamController;
MyNavObserver({required this.streamController});
@override
void didPop(Route route, Route? previousRoute) {
if (previousRoute != null) {
if (previousRoute.settings.name == null) {
streamController.add(3);
} else {
streamController
.add(int.parse(previousRoute.settings.name!.split('/').last));
}
}
}
@override
void didPush(Route route, Route? previousRoute) {
if (route.settings.name == null) {
streamController.add(3);
} else {
streamController.add(int.parse(route.settings.name!.split('/').last));
}
}
}
并使用 StreamController
,您可以通过将 SidebarTemplate
放入 StreamBuilder
来更改您的 SidebarTemplate
。这将处理您在问题中提到的所有要求。
查看实例 here。
在我的应用程序中,我希望有一个侧边栏,允许我在我的应用程序的任何地方访问特定功能。
我想要什么:
- 当我推送我的页面时侧边栏仍然可见
- 我可以使用侧边栏功能之一推送命名路线或打开模式
- 我无法在某些页面上显示边栏
我是做什么的:
红色是执着sidebar
,黄色是我的app content
。
如果我在 HomeView
中单击我的 profil button
,则会显示 ProfilView
并且我的侧边栏仍然可见,所以没关系
我的AppView
:
class AppView extends StatelessWidget {
const AppView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: AppConfig.kAppName,
debugShowCheckedModeBanner: false,
theme: AppTheme().data,
builder: (context, child) => SidebarTemplate(child: child), // => I create a template
onGenerateRoute: RouterClass.generate,
initialRoute: RouterName.kHome,
);
}
我的SidebarTemplate
:(显示侧边栏并使用我的路由器加载页面)
class SidebarTemplate extends StatelessWidget {
final Widget? child;
const SidebarTemplate({Key? key, this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body : Row(
children: [
SidebarAtom(), // => My sidebar Widget
Expanded(
child: ClipRect(
child: child! // => My view
),
)
],
)
),
);
}
}
我的 RouterClass
:
abstract class RouterClass{
static Route<dynamic> generate(RouteSettings settings){
final args = settings.arguments;
switch(settings.name){
case RouterName.kHome:
return MaterialPageRoute(
builder: (context) => HomeView()
);
case RouterName.kProfil:
return MaterialPageRoute(
builder: (context) => ProfilView(title: "Profil",)
);
default:
return MaterialPageRoute(
builder: (context) => Error404View(title: "Erreur")
);
}
}
}
怎么做:
- 因为我有一个错误,所以要从我的边栏中使用按钮 pushNamed 或打开模式
The following assertion was thrown while handling a gesture:
I/flutter (28519): Navigator operation requested with a context that does not include a Navigator.
I/flutter (28519): The context used to push or pop routes from the Navigator must be that of a widget that is a
I/flutter (28519): descendant of a Navigator widget.
- 在我想要的时候隐藏边栏,例如
SplashScreen
任何有关实现此目标的最佳方法的指导将不胜感激。
正如您从 Profil
屏幕截图中看到的那样,边栏不是 Navigator
的小部件子树的一部分(后退按钮仅在配置文件小部件上)。这意味着您无法从侧边栏的 context
中找到 Navigator
。发生这种情况是因为您在 MaterialApp
中使用了 builder
,其中 inserts widgets above the navigator.
这也是为什么当你想显示启动画面时不能隐藏侧边栏的原因。
您真的需要在 MaterialApp
上使用 builder
吗?然后您可以全局保存导航器并从侧边栏访问它。 This is the first article when I search on DuckDuckGo,你可以关注。
要显示 SplashScreen,您需要向 AppView
添加状态并更改 builder
函数。如果你问我不是很好
我建议您重新考虑您的体系结构并删除 MaterialApp
中的 builder
。
你可以用一个NavigatorObserver
来监听路由的变化
class MyNavObserver with NavigatorObserver {
final StreamController<int> streamController;
MyNavObserver({required this.streamController});
@override
void didPop(Route route, Route? previousRoute) {
if (previousRoute != null) {
if (previousRoute.settings.name == null) {
streamController.add(3);
} else {
streamController
.add(int.parse(previousRoute.settings.name!.split('/').last));
}
}
}
@override
void didPush(Route route, Route? previousRoute) {
if (route.settings.name == null) {
streamController.add(3);
} else {
streamController.add(int.parse(route.settings.name!.split('/').last));
}
}
}
并使用 StreamController
,您可以通过将 SidebarTemplate
放入 StreamBuilder
来更改您的 SidebarTemplate
。这将处理您在问题中提到的所有要求。
查看实例 here。