Flutter 如何在颤振应用程序上覆盖小部件?
我想要一个小部件,将坐在整个应用程序的顶部。当我尝试使用Flutter 如何在颤振应用程序上覆盖小部件?,flutter,flutter-layout,Flutter,Flutter Layout,我想要一个小部件,将坐在整个应用程序的顶部。当我尝试使用Overlay.of(context).insert执行此操作时,覆盖将在替换该路由后消失。是否有一种方法可以让我的应用程序上有一个小部件,即使屏幕稍后弹出?您是否尝试添加一个导航器作为脚手架的子/后代?据我所知,默认导航器位于MaterialApp中,它高于一切。当您添加自己的导航器时,您的路由将发生在树中的脚手架下,而不是其上方 可能存在一种更优化的方式,但作为一种选择,这是一个具有两个页面的示例,本地导航器和覆盖 import 'pa
Overlay.of(context).insert执行此操作时,覆盖将在替换该路由后消失。是否有一种方法可以让我的应用程序上有一个小部件,即使屏幕稍后弹出?您是否尝试添加一个导航器作为脚手架的子/后代?据我所知,默认导航器位于MaterialApp
中,它高于一切。当您添加自己的导航器
时,您的路由将发生在树中的脚手架
下,而不是其上方 可能存在一种更优化的方式,但作为一种选择,这是一个具有两个页面的示例,本地导航器和覆盖
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _navigatorKey = GlobalKey<NavigatorState>();
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: WillPopScope(
onWillPop: () async => !await _navigatorKey.currentState.maybePop(),
child: LayoutBuilder(
builder: (context, constraints) {
WidgetsBinding.instance.addPostFrameCallback((_) => _insertOverlay(context));
return Navigator(
key: _navigatorKey,
onGenerateRoute: (RouteSettings settings) {
switch (settings.name) {
case '/page2':
return MaterialPageRoute(builder: (_) => Page2());
default:
return MaterialPageRoute(builder: (_) => Page1(_navigatorKey));
}
},
);
},
),
),
);
}
void _insertOverlay(BuildContext context) {
return Overlay.of(context).insert(
OverlayEntry(builder: (context) {
final size = MediaQuery.of(context).size;
print(size.width);
return Positioned(
width: 56,
height: 56,
top: size.height - 72,
left: size.width - 72,
child: Material(
color: Colors.transparent,
child: GestureDetector(
onTap: () => print('ON TAP OVERLAY!'),
child: Container(
decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.redAccent),
),
),
),
);
}),
);
}
}
class Page1 extends StatelessWidget {
final GlobalKey<NavigatorState> navigatorKey;
Page1(this.navigatorKey);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.green[200],
appBar: AppBar(title: Text('Page1')),
body: Container(
alignment: Alignment.center,
child: RaisedButton(
child: Text('go to Page2'),
onPressed: () => navigatorKey.currentState.pushNamed('/page2'),
),
),
);
}
}
class Page2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.yellow[200],
appBar: AppBar(title: Text('back to Page1')),
body: Container(
alignment: Alignment.center,
child: Text('Page 2'),
),
);
}
}
导入“包装:颤振/材料.省道”;
void main()=>runApp(MyApp());
类MyApp扩展了StatefulWidget{
@凌驾
_MyAppState createState()=>\u MyAppState();
}
类MyAppState扩展了状态{
最终_navigatorKey=GlobalKey();
@凌驾
小部件构建(构建上下文){
返回材料PP(
debugShowCheckedModeBanner:false,
家:威尔波普(
onWillPop:()异步=>!等待_navigatorKey.currentState.maybePop(),
子:布局生成器(
生成器:(上下文、约束){
WidgetsBinding.instance.addPostFrameCallback(()=>insertOverlay(上下文));
返回导航器(
键:_导航工作,
onGenerateRoute:(路由设置){
开关(设置.名称){
案例“/page2”:
返回MaterialPackageRoute(生成器:()=>Page2());
违约:
返回物料管理路线(生成器:()=>Page1(navigatorKey));
}
},
);
},
),
),
);
}
void\u insertOverlay(构建上下文){
返回Overlay.of(上下文).insert(
覆盖入口(生成器:(上下文){
最终大小=MediaQuery.of(context).size;
打印(大小、宽度);
返回定位(
宽度:56,
身高:56,
顶部:尺寸。高度-72,
左:size.width-72,
儿童:材料(
颜色:颜色。透明,
儿童:手势检测器(
onTap:()=>打印('ON-TAP OVERLAY!'),
子:容器(
装饰:框装饰(形状:BoxShape.circle,颜色:Colors.redAccent),
),
),
),
);
}),
);
}
}
类Page1扩展了无状态小部件{
最后的环球航行;
第1页(本页为导航工作);
@凌驾
小部件构建(构建上下文){
返回脚手架(
背景颜色:颜色。绿色[200],
appBar:appBar(标题:文本('Page1')),
主体:容器(
对齐:对齐.center,
孩子:升起按钮(
子项:文本(“转到第2页”),
onPressed:()=>navigatorKey.currentState.PushName('/page2'),
),
),
);
}
}
类Page2扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回脚手架(
背景颜色:颜色。黄色[200],
appBar:appBar(标题:文本(“返回到第1页”),
主体:容器(
对齐:对齐.center,
子项:文本(“第2页”),
),
);
}
}
阅读评论后,找到
创建了一个覆盖,将坐在上面的一切
可以从任何地方调用
只需遵循4个简单步骤
步骤1:在main.dart中:
类MyApp扩展了无状态小部件{
//此小部件是应用程序的根。
@凌驾
小部件构建(构建上下文){
返回材料PP(
home:Stack(这样做会使使用android上的back按钮关闭应用程序…:(这个例子将我推向了我的用例的正确方向。我知道它不是MaterialApp的“原始”导航器),而是一个嵌套的新方法。这种方法有什么缺点吗?这会不会在每一帧后继续在其顶部插入覆盖层?还有,您试图从\u insertOverlay
方法返回什么?。insert(…)
返回void。您是否想过在MaterialApp中使用堆栈作为主页
?
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Stack( <-- using stack
children: [
MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
),
OverlayView(),<-- my overlay widget
],
),
);
}
}
class OverlayView extends StatelessWidget {
const OverlayView({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<bool>( <--- IMP , using ValueListenableBuilder for showing/removing overlay
valueListenable: Loader.appLoader.loaderShowingNotifier,
builder: (context, value, child) {
if (value) {
return yourOverLayWidget(); <-- your awesome overlay
} else {
return Container();
}
},
);
}
class Loader {
static final Loader appLoader = Loader(); <-- singleton
ValueNotifier<bool> loaderShowingNotifier = ValueNotifier(false);
ValueNotifier<String> loaderTextNotifier = ValueNotifier('error message');
void showLoader() { <-- using to show from anywhere
loaderShowingNotifier.value = true;
}
void hideLoader() { <-- using to hide from anywhere
loaderShowingNotifier.value = false;
}
void setText({String errorMessage}) { <-- using to change error message from anywhere
loaderTextNotifier.value = errorMessage;
}
void setImage() { <-- DIY
// same as that of setText //
}
}
void _incrementCounter() async {
Loader.appLoader.showLoader(); <-- show loder
Loader.appLoader.setText(errorMessage: 'this is custom error message');<-- set custom message
await Future.delayed(Duration(seconds: 5)); <-- im hiding it after 5 sec
Loader.appLoader.hideLoader(); <-- do whatever you want
}