我想在整个应用程序上显示覆盖,因此我尝试在 MaterialApp(根小部件)的上下文中插入覆盖条目,但问题是我在调用以下方法时得到空值:
Overlay.of(context);
GetMaterialApp.router(
debugShowCheckedModeBanner: false,
theme: AppTheme.lightTheme,
scaffoldMessengerKey: Keys.scaffold,
scrollBehavior: MyCustomScrollBehavior(),
routeInformationParser: WebRoutes.goRouter.routeInformationParser,
routerDelegate: WebRoutes.goRouter.routerDelegate,
routeInformationProvider: WebRoutes.goRouter.routeInformationProvider,
builder: (context, child) {
WidgetsBinding.instance.addPostFrameCallback((_){
addOverlay(context);
});
return child;
}
void addOverlay(BuildContext context) {
print(Overlay.of(context));
return Overlay.of(context)?.insert(OverlayEntry(
builder: (context) {
return SomeWidget();
},
));
}
有什么方法可以使用此根小部件的上下文来获取叠加层的状态,因为我想全局显示叠加层。
非常感谢,如果有人帮助我,我真的很感激。
MaterialApp(
navigatorKey: getIt.get<NavigatorService>().navigatorKey,
theme: AppTheme.defaultTheme,
initialRoute: AppRoutes.splashScreen,
builder: (context, child) {
return Scaffold(
body: Stack(
children: [
child!,
Positioned(
top: 15,
child: Container(
color: Colors.red,
height: 50,
width: MediaQuery.of(context).size.width,
child: const Center(child: Text("HI I AM AN OVERLAY")),
),
),
],
),
);
},
onGenerateRoute: AppRoutes.onGenerateRoute,
),
您可以通过创建一个负责显示/删除覆盖的类来实现,该类在创建时需要接收一个
BuildContext
才能创建Overlay
的实例。
基本上你需要做的是:
创建一个类
OverlayScreen
来构建OverlayState
&& OverlayEntry
(在这种情况下,OverylayEntry
将是一个OverlayEntry列表,因为我们可能在屏幕上有多个Overlay,所以我们可以将它们全部删除)立刻)。
先在您的应用程序中创建此类的实例(例如 MyApp)。在您的情况下,您需要在 Material.router...builder param 中调用它。
在主页中访问此
overlayScreen
以显示|删除所有叠加层
让我们创建我们的 OverlayScreen
import 'package:flutter/material.dart';
class OverlayScreen {
/// Create an Overlay on the screen
/// Declared [overlayEntrys] as List<OverlayEntry> because we might have
/// more than one Overlay on the screen, so we keep it on a list and remove all at once
BuildContext _context;
OverlayState? overlayState;
List<OverlayEntry>? overlayEntrys;
void closeAll() {
for (final overlay in overlayEntrys ?? <OverlayEntry>[]) {
overlay.remove();
}
overlayEntrys?.clear();
}
void show() {
overlayEntrys?.add(
OverlayEntry(
builder: (context) {
return _buildOverlayWidget();
},
),
);
overlayState?.insert(overlayEntrys!.last);
}
OverlayScreen._create(this._context) {
overlayState = Overlay.of(_context);
overlayEntrys = [];
}
factory OverlayScreen.of(BuildContext context) {
return OverlayScreen._create(context);
}
Widget _buildOverlayWidget() {
return Positioned(
top: 20,
left: 20,
right: 20,
child: Container(
width: 300,
color: Colors.black,
height: 300,
child: const Text("MY CHAT"),
),
);
}
}
现在让我们在
MyApp
上创建一个实例
// Need to have it global to be able to access everywhere
OverlayScreen? overlayScreen;
void main() {
runApp(
const MyApp(),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: const HomePage(),
builder: (context, child) {
return Overlay(
initialEntries: [
OverlayEntry(
builder: (context) {
// Create an instance of `OverlayScreen` to be accessed globally
overlayScreen = OverlayScreen.of(context);
return child ?? const SizedBox();
},
),
],
);
},
);
}
}
为了最终确定,让我们创建我们的
HomePage
并在那里访问我们的 overlayScreen
import 'package:flutter/material.dart';
import 'package:overlay_all_app/src/overlay_screen.dart';
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
// Create an instance of OverlayScreen
final overlayScreen = OverlayScreen.of(context);
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
onPressed: () {
// display the overlay
overlayScreen.show();
},
child: const Text('Display Overlay'),
),
const SizedBox(height: 30),
TextButton(
onPressed: () {
// Call your next screen here
},
child: const Text('Go to next page'),
),
const SizedBox(height: 30),
TextButton(
onPressed: () {
// removed all overlays on the screen
overlayScreen.closeAll();
},
child: const Text('Close Overlay'),
),
],
),
),
);
}
}
就是这样。您可以使用此类 OverlayScreen 在任何您想要的地方显示/删除All。
我使用示例代码创建了一个 PR,请查看 https://github.com/antonio-nicolau/flutter-working-with-overlay
import 'package:flutter/material.dart';
import 'package:get/get_navigation/src/root/get_material_app.dart';
import 'package:go_router/go_router.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(App2());
}
class App2 extends StatelessWidget {
App2({super.key});
final _router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => const OverlayWrapper(),
),
],
);
@override
Widget build(BuildContext context) {
return GetMaterialApp.router(
routeInformationParser: _router.routeInformationParser,
routerDelegate: _router.routerDelegate,
routeInformationProvider: _router.routeInformationProvider,
);
}
}
class OverlayWrapper extends StatefulWidget {
const OverlayWrapper({Key? key}) : super(key: key);
@override
State<OverlayWrapper> createState() => _OverlayWrapperState();
}
class _OverlayWrapperState extends State<OverlayWrapper> {
@override
void initState() {
super.initState();
}
showOverLay() {
OverlayEntry overlayEntry = OverlayEntry(
builder: (context) => Container(
color: Colors.red,
child: const Text('data'),
),
);
Overlay.of(context).insert(overlayEntry);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
showOverLay();
},
child: const Text(
'ShowOverlay',
style: TextStyle(),
),
),
),
);
}
}
鉴于问题是关于如何添加 使用 .router Navigator 2.0 进行覆盖。最好的方法是将导航器小部件包装在 RouterDelegate 的构建方法中的覆盖层中,如下所示:
class AppRouterDelegate extends RouterDelegate<AppRoute> with ChangeNotifier, PopNavigatorRouterDelegateMixin<AppRoute> {
final PageNotifier notifier;
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
final SideMenu _sidMenu = const SideMenu();
final GlobalKey<NavigatorState> _navigatorKey;
AppRouterDelegate({required this.notifier}) : _navigatorKey = GlobalKey<NavigatorState>();
@override
GlobalKey<NavigatorState> get navigatorKey => _navigatorKey;
@override
Widget build(BuildContext context) {
//THIS EXAMPLE SHOWS USING A SCAFFOLD IN THE OVERLAY WITH A SIDE MENU AND BUTTON
return Overlay(
initialEntries: [
OverlayEntry(
builder: (context) => Scaffold(
key: _scaffoldKey,
drawer: _sidMenu, //UTILIZE THE DRAWER PROPERTY FOR A SIDE MENU
body: Stack(
children: [
Navigator(
key: navigatorKey,
pages: [
//YOUR PAGE LOGIC
]
),
Positioned( // ADD AN ICON TO OPEN SIDE MENU
top: 10.0,
left: 10.0,
child: IconButton(
icon: const Icon(Icons.menu, size: 30.0),
onPressed: () {
_scaffoldKey.currentState!.openDrawer();
},
),
),
],
),
),
),
],
);
}
//Rest of your router delegate code
}