I am trying to add a background image which is always there no matter which route is active. I the example below is inspired by this answer but the background will only be visible for the route "/". I was hoping to not have to set the background image for each route. Any suggestions?
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/camping-background.png"),
fit: BoxFit.cover),
),
routes: <String, WidgetBuilder>{
'/login': (BuildContext context) => const Login(),
'/register': (BuildContext context) => const Register(),
'/home': (BuildContext context) => const Home(),
},
);
}
CodePudding user response:
You may use the builder
field on MaterialApp
to provide a TransitionBuilder function that defines a common wrapper for all routes:
import 'package:flutter/material.dart';
void main() {
runApp(Example());
}
class Example extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
builder: (context, child) => DecoratedBox(
decoration: const BoxDecoration(
image: DecorationImage(
image: NetworkImage("https://flutter.github.io/assets-for-api-docs/assets/widgets/owl-2.jpg"),
fit: BoxFit.cover,
),
),
child: child,
),
initialRoute: '/login',
routes: <String, WidgetBuilder>{
'/login': (BuildContext context) => Login(),
'/home': (BuildContext context) => Home(),
},
);
}
}
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
const Text('Home'),
ElevatedButton(onPressed: () => Navigator.of(context).pop(), child: const Text('Go back')),
]
);
}
}
class Login extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
const Text('Login'),
ElevatedButton(onPressed: () => Navigator.of(context).pushNamed('/home'), child: const Text('Login')),
]
);
}
}
It takes a BuildContext
as well as the currently rendered route as child
as arguments and returns a Widget that is then displayed as the route.
Also since it seemed like there was some confusion with regards to the usage of home
and routes
, here is a snipped from the MaterialApp
docs:
- For the / route, the home property, if non-null, is used.
- Otherwise, the routes table is used, if it has an entry for the route.
- Otherwise, onGenerateRoute is called, if provided. It should return a non-null value for any valid route not handled by home and routes.
- Finally if all else fails onUnknownRoute is called.
While you could use home
and routes
together, I personally thing it's more clear what's going on with routes using only routes
in addition to initialRoute
to indicate which is first (unless it is indeed /
which is the default).
CodePudding user response:
Copy & Paste it on dartpad to see the results
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class BaseLayout extends StatelessWidget {
final Widget? child;
const BaseLayout({Key? key, @required this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
width: 720,
decoration: const BoxDecoration(
image: DecorationImage(
image: NetworkImage(
"https://images.pexels.com/photos/440731/pexels-photo-440731.jpeg"),
fit: BoxFit.fill),
),
child: child,
);
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Home')),
body: BaseLayout(child: Home()),
),
routes: <String, WidgetBuilder>{
'/login': (BuildContext context) => Login(),
'/register': (BuildContext context) => Register(),
'/home': (BuildContext context) => Home(),
},
);
}
}
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
const Text('HOMEPAGE', style: TextStyle(fontSize: 32)),
const SizedBox(height: 12),
ElevatedButton(
child: const Text('Login'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Scaffold(
appBar: AppBar(title: const Text('Login')),
body: BaseLayout(child: Login())),
),
);
},
),
const SizedBox(height: 12),
ElevatedButton(
child: const Text('Register'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BaseLayout(child: Register())),
);
},
),
const SizedBox(height: 12),
ElevatedButton(
child: const Text('No Background Image Screen'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NoBackground()),
);
},
),
],
);
}
}
class Login extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(
'Login',
style: Theme.of(context).textTheme.headline4,
),
const SizedBox(height: 12),
ElevatedButton(
child: const Text('Back to Homepage'),
onPressed: () {
Navigator.pop(context);
},
),
],
);
}
}
class Register extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(
'Register!',
style: Theme.of(context).textTheme.headline4,
),
const SizedBox(height: 12),
ElevatedButton(
child: const Text('Back to Homepage'),
onPressed: () {
Navigator.pop(context);
},
),
],
);
}
}
class NoBackground extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
const Text(
'No Background Image!',
style: TextStyle(color: Colors.white),
),
const SizedBox(height: 12),
ElevatedButton(
child: const Text('Back to Homepage'),
onPressed: () {
Navigator.pop(context);
},
),
],
);
}
}
Complete with scaffold app bar & no background image sample
Check it on Gist: Complete code here