Я пытаюсь добавить фоновое изображение, которое всегда есть независимо от того, какой маршрут активен. Пример ниже вдохновлен этим ответом, но фон будет виден только для маршрута «/». Я надеялся, что мне не нужно будет устанавливать фоновое изображение для каждого маршрута. Какие-либо предложения?
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(),
},
);
}
Ради фонового изображения вы можете просто обернуть свой MaterialApp в DecoratedBox. Это предпочтительнее другого подхода (изложенного ниже), потому что он злоупотребляет builder
, который предназначен для других целей:
Конструктор для вставки виджетов над навигатором или — при использовании конструктора WidgetsApp.router — над маршрутизатором, но ниже других виджетов, созданных виджетом WidgetsApp, или для полной замены навигатора/маршрутизатора.
Поскольку MaterialApp
настраивает исключительно не отображаемые виджеты, а DecoratedBox
не полагается ни на один из них, он может просто служить родительским виджетом для остальной части приложения, достигая желаемого эффекта.
import 'package:flutter/material.dart';
void main() {
runApp(Example());
}
class Example extends StatelessWidget {
@override
Widget build(BuildContext context) {
return 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: MaterialApp(
title: 'Flutter Demo',
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')),
]
);
}
}
Вы можете использовать поле builder в MaterialApp
, чтобы предоставить функцию TransitionBuilder, которая определяет общую оболочку для всех маршрутов:
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')),
]
);
}
}
Он принимает BuildContext
, а также текущий отображаемый маршрут в качестве child
в качестве аргументов и возвращает виджет, который затем отображается как маршрут.
Кроме того, поскольку возникла некоторая путаница в отношении использования home
и routes
, вот вырезка из документации MaterialApp
:
- Для маршрута / используется свойство home, если оно не равно null.
- В противном случае используется таблица маршрутов, если в ней есть запись для маршрута.
- В противном случае вызывается onGenerateRoute, если он предоставлен. Он должен возвращать ненулевое значение для любого допустимого маршрута, не обработанного home и route.
- Наконец, если ничего не помогает, вызывается onUnknownRoute.
Хотя вы можете использовать home
и routes
вместе, я лично считаю, что более понятно, что происходит с маршрутами, использующими только routes
в дополнение к initialRoute
, чтобы указать, какой из них является первым (если только это действительно не /
, который используется по умолчанию).
Не за что! Я только что добавил еще один (возможно, лучший) подход вверху ответа, если вы тоже хотите взглянуть на это @Michael. Я также привел некоторые рассуждения относительно того, почему я считаю, что это лучше, чем то, что я опубликовал вчера :)
Скопируйте и вставьте его на дротик, чтобы увидеть результаты.
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);
},
),
],
);
}
}
В комплекте с панелью приложений скаффолда и без образца фонового изображения
Проверьте это на Gist: полный код здесь
Спасибо за пример и пояснение!