问题
My application has a lot of routes and almost every route uses Scaffold with the same Drawer menu to navigate inside the app (my own CustomDrawer widget). As for devices with big screen, I want to always show the menu on the left side in layout, instead of using Drawer (it works like this in Gmail app. I attached a pic). In other words, I need to make a responsive layout with fixed menu.
What I've tried:
- I know that you can use LayoutBuilder to learn constraints size;
- Making same layout inside every route will work, but it's bad solution because each route will build menu for itself (scroll position will be different, there will be many states for many menus etc.). I need one app-wide menu for many different routes, but it's impossible to make layout on top routes;
- Squashing all routes into one route with changing state of main content will take a lot of refactoring and doesn't sound good at all.
In React the app layout would look something like this:
<App>
<Menu />
<main className="content">
<Switch>
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
<Route path="/" component={Home} />
</Switch>
</main>
</App>
But I have no idea how to make something like this in Flutter.
tl;dr: To make UI responsive for big screens, I want to show fixed menu instead of Drawer. One menu for whole app, not for every route.
回答1:
The trick was to use a nested navigator. If viewport's width is big, I put a menu in a row with content, otherwise pass a menu to Scaffold
as drawer
parameter.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
MyHomePage({Key key, this.title}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final routes = List.generate(20, (i) => 'test $i');
final navigatorKey = GlobalKey<NavigatorState>();
bool isMenuFixed(BuildContext context) {
return MediaQuery.of(context).size.width > 500;
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final menu = Container(
color: theme.canvasColor,
child: SafeArea(
right: false,
child: Drawer(
elevation: 0,
child: ListView(
children: <Widget>[
for (final s in routes)
ListTile(
title: Text(s),
onTap: () {
// Using navigator key, because the widget is above nested navigator
navigatorKey.currentState.pushNamedAndRemoveUntil(s, (r) => false);
// navigatorKey.currentState.pushNamed(s);
},
),
],
),
)
)
);
return Row(
children: <Widget>[
if (isMenuFixed(context))
menu,
Expanded(
child: Navigator(
key: navigatorKey,
initialRoute: '/',
onGenerateRoute: (settings) {
return MaterialPageRoute(
builder: (context) {
return Scaffold(
appBar: AppBar(
title: Text(settings.name),
),
body: SafeArea(
child: Text(settings.name),
),
drawer: isMenuFixed(context) ? null : menu,
);
},
settings: settings
);
},
),
),
],
);
}
}
来源:https://stackoverflow.com/questions/58877550/making-fixed-app-wide-menu-instead-of-drawer-on-tablets-in-flutter