Я работал над проектом, который требует, чтобы я изменил виджет на экране на основе orientation
.
мобильного устройства. Например, в случае ориентации portrait
мне нужно показать виджет (скажем, портретный виджет) и в случае ориентации landscape
мне нужно показать другой виджет (назовем его ландшафтным виджетом).
Я использовал OrientationBuilder
Актуальная проблема: При изменении ориентации все Dialogs
и OptionMenu
или любой другой виджет всплывающего вида не закрывается. Как мне закрыть их при смене ориентации?
Действия по воспроизведению проблемы:
- Запустите приведенный ниже код приложения [пример приложения для воспроизведения проблемы]
- Сделайте долгое нажатие на теле приложения, чтобы увидеть диалоговое окно или щелкните
OptionMenu
в верхнем левом углу - Измените ориентацию устройства, вы увидите, что тело виджета изменилось в соответствии с ориентацией, но виджет
Popuped
все еще виден.
пример кода приложения:
// main.dart
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 StatelessWidget {
@override
Widget build(BuildContext context) {
return OrientationBuilder(builder: (context, orientation) {
bool isLandscape = orientation == Orientation.landscape;
return isLandscape ? Landscape() : Portrait();
});
}
}
class Portrait extends StatefulWidget {
@override
_PortraitState createState() => _PortraitState();
}
class _PortraitState extends State<Portrait> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: buildTitle(),
actions: <Widget>[_buildOptionMenu(context)],
),
body: GestureDetector(
onLongPress: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
content: buildTitle(),
),
);
},
child: Container(
color: Colors.blue.withOpacity(0.4),
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Center(
child: buildTitle(),
),
],
),
),
),
);
}
Widget _buildOptionMenu(BuildContext context) {
return PopupMenuButton(itemBuilder: (context) {
var list = <String>['Portrait-Item-1', 'Portrait-Item-2'];
return list
.map<PopupMenuEntry<String>>(
(e) => PopupMenuItem<String>(
child: Text(e),
),
)
.toList();
});
}
Text buildTitle() => Text('Portrait');
}
class Landscape extends StatefulWidget {
@override
_LandscapeState createState() => _LandscapeState();
}
class _LandscapeState extends State<Landscape> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: buildTitle(),
actions: <Widget>[_buildOptionMenu(context)],
),
body: GestureDetector(
onLongPress: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
content: buildTitle(),
),
);
},
child: Container(
color: Colors.orange.withOpacity(0.3),
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Center(
child: buildTitle(),
),
],
),
),
),
);
}
Text buildTitle() => Text('Landscape');
Widget _buildOptionMenu(BuildContext context) {
return PopupMenuButton(itemBuilder: (context) {
var list = <String>[
'Landscape-Item-1',
'Landscape-Item-2',
'Landscape-Item-3',
];
return list
.map<PopupMenuEntry<String>>(
(e) => PopupMenuItem<String>(
child: Text(e),
),
)
.toList();
});
}
}
Я не смог найти подходящее решение. Есть некоторые решения, которые требуют прислушиваться к изменениям ориентации и push / pop виджетам, основанным на новой ориентации.
Но работать с ним слишком сложно, и для него требуется добавить код одного и того же типа как в книжной, так и в альбомной ориентации. Что также не масштабируется в случае, если мне нужно обрабатывать дополнительные ориентации, такие как, обратный портрет и обратный ландшафт.
Обновление
Одно из возможных решений - это вытолкнуть все виджеты до виджета root, а затем pu sh новый виджет на основе ориентации. Это работает, но имеет побочный эффект.
Например, если я наберу sh какой-нибудь новый виджет из портрета (скажем, страницу входа).
Затем, если я поверну свое устройство в альбомную ориентацию, оно должно наполнить интерфейс страницы входа в систему в альбомной ориентации, но в соответствии с кодом, который отображает весь виджет до root.
То, что я увижу, это виджет Пейзаж вместо страницы входа в альбомном режиме.
Для ясности :
Я ищу ответ закрыть все открытые диалоги / всплывающие окна до того, как родительский виджет станет disposed
. Решение не должно зависеть от извлечения всего виджета из навигатора.
Что-то, что я узнал из представления дерева виджетов, состоит в том, что виджеты, которые отображаются как всплывающее окно (всплывающее окно) меню или диалоговое окно) находятся в другой ветке виджета непосредственно из MaterialApp
.
Проверьте эти снимки экрана:
Видимое всплывающее меню в виджете Пейзаж:
Видимый диалог в виджете Пейзаж:
Видимое всплывающее меню в виджете Портрет:
Видимый диалог в виджете Портрет:
Итак, в основном Я ищу способ найти и открыть все эти типы виджетов, которые мы можем открыть перед удалением родительского виджета. Я думаю, это должно быть применимо ко всем экранам виджетов и не должно изменять существующее дерево виджетов над текущим виджетом.