SharedPreferences value needs to be reset every other time - flutter

So,in this included flutter code,I am using a if loop in checkFirstSeen() to set my seen boolean to a value. This will then set my SharedPreferences value for the app. However,on every other restart of the application,I have to press the GotoHomepage button as opposed to it working automatically based off of the SharedPreferences value that was set. How can I fix this?
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:audiotest/UI/homepage.dart';
void main() => runApp(new MaterialApp(
title: "TestAudio",
initialRoute: '/intro_route',
routes: {
'/intro_route': (context) => IntroScreen(),
'/homescreen_route': (context) => MainPersistentTabBar2(),
}));
class IntroScreen extends StatefulWidget {
#override
IntroScreenstate2 createState() => IntroScreenstate2();
}
class IntroScreenstate2 extends State<IntroScreen> {
bool buttonstatus = true;
Future checkFirstSeen() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool seen = (prefs.getBool('seen') ?? false);
prefs.setBool('seen', false);
if (buttonstatus == false) {
prefs.setBool('seen', true);
}
if (seen == true) {
Navigator.pushNamed(context, '/homescreen_route');
} else {
}
}
#override
void initState() {
super.initState();
new Timer(new Duration(milliseconds: 1), () {
checkFirstSeen();
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text('This is the placeholder for the TOS'),
new MaterialButton(
child: new Text('Go to Home Page'),
onPressed: () {
buttonstatus = false;
checkFirstSeen();
//Navigator.pushNamed(context, '/homescreen_route');
},
)
],
),
),
);
}
}

You can copy paste run full code below
You can get seen in main() and check seen directly in initialRoute
code snippet
bool seen;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences prefs = await SharedPreferences.getInstance();
seen = await prefs.getBool("seen");
await prefs.setBool("seen", true);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
...
initialRoute:
seen == false || seen == null ? "/intro_route" : "/homescreen_route",
routes: {
'/homescreen_route': (context) => MainPersistentTabBar2(
title: "demo",
),
"/intro_route": (context) => IntroScreen(),
},
);
}
}
working demo
full code
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter/services.dart';
bool seen;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences prefs = await SharedPreferences.getInstance();
seen = await prefs.getBool("seen");
await prefs.setBool("seen", true);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute:
seen == false || seen == null ? "/intro_route" : "/homescreen_route",
routes: {
'/homescreen_route': (context) => MainPersistentTabBar2(),
"/intro_route": (context) => IntroScreen(),
},
);
}
}
class MainPersistentTabBar2 extends StatefulWidget {
#override
MainPersistentTabBarState2 createState() => MainPersistentTabBarState2();
}
class MainPersistentTabBarState2 extends State<MainPersistentTabBar2> {
Brightness brightness;
#override
Widget build(BuildContext context) {
return new MaterialApp(
theme: new ThemeData(
primarySwatch: Colors.blue,
brightness: Brightness.dark,
),
home: DefaultTabController(
length: 4,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
isScrollable: true,
tabs: <Widget>[
Container(
width: 90,
height: 40,
alignment: Alignment.center,
child: Text("Session 1"),
),
Container(
width: 90,
height: 40,
alignment: Alignment.center,
child: Text("Session 2"),
),
Container(
width: 90,
height: 40,
alignment: Alignment.center,
child: Text("Session 3"),
),
Container(
width: 90,
height: 40,
alignment: Alignment.center,
child: Text("Session 4"),
),
],
),
title: Text('Own The Tone '),
/*actions: <Widget>[
PopupMenuButton<String>(
onSelected: _choiceAction,
itemBuilder: (BuildContext context) {
return Constants.choices.map((String choice) {
return PopupMenuItem<String>(
value: choice,
child: Text(choice),
);
}).toList();
},
)
],*/
),
body: TabBarView(
children: <Widget>[
FirstScreen(),
Center(child: Text("Sample two")),
Center(child: Text("Sample three")),
Center(child: Text("Sample four")),
],
),
),
),
);
}
// This area controls the settings menus
/* void _choiceAction(String choice) {
if (choice == Constants.about) {
Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('About the app'),
),
body: new PageView(),
);
}));
} else if (choice == Constants.settings) {
Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Settings'),
),
body: new Container(
child: Center(
child: Text('placeholder'),
)),
);
}));
}
}*/
}
class FirstScreen extends StatefulWidget {
#override
_FirstScreenState createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("First Screen"),
),
body: Text("First"));
}
}
class IntroScreen extends StatefulWidget {
#override
_IntroScreenState createState() => _IntroScreenState();
}
class _IntroScreenState extends State<IntroScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Introduction"),
),
body: Text("Intro"));
}
}

Related

Bad state: Cannot emit new states after calling close

I'm using flutter_form_bloc (https://pub.dev/packages/flutter_form_bloc) and I created two classes, the first is the login page:
class LoginScreen extends StatelessWidget {
const LoginScreen({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter - Parse Server',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: FutureBuilder<bool>(
future: hasUserLogged(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return SafeArea(
child: Scaffold(
body: Center(
child: Container(
width: 100,
height: 100,
child: CircularProgressIndicator()),
),
),
);
default:
if (snapshot.hasData && snapshot.data!) {
return UserPage();
} else {
return LoginPage();
}
}
}),
);
}
}
class LoginPage extends StatefulWidget {
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final controllerUsername = TextEditingController();
final controllerPassword = TextEditingController();
final controllerConfirmPassword = TextEditingController();
bool isLoggedIn = false;
#override
Widget build(BuildContext context) {
return SafeArea(
child: SafeArea(
child: Scaffold(
body: SingleChildScrollView(
...
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Don\'t have an Account? ',
overflow: TextOverflow.ellipsis,
),
new InkWell(
child: new Text(
'Sign Up',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
onTap: () => Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (_) =>
const listRegistrationScreen2()))),
],
),
),
);
}
class UserPage extends StatelessWidget {
...
}
And the second is list registration:
class listRegistrationScreen2 extends StatelessWidget {
const listRegistrationScreen2({super.key});
#override
Widget build(BuildContext context) {
return _listRegistrationScreen();
}
}
class _listRegistrationScreen extends StatefulWidget {
#override
__listRegistrationScreen createState() => __listRegistrationScreen();
}
class __listRegistrationScreen extends State<_listRegistrationScreen> {
static var flag = false;
...
#override
void initState() {
formBloc = null;
super.initState();
}
#override
void dispose() {
formBloc = null;
super.dispose();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
iconTheme: IconThemeData(
color: Colors.black,
),
centerTitle: true,
actions: [
IconButton(
onPressed: () {
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (_) => const LoginScreen()));
},
icon: Icon(Icons.arrow_back))
],
),
body: BlocProvider(
create: (context) => ConditionalFieldsForm(),
child: Builder(
builder: (context) {
formBloc = BlocProvider.of<ConditionalFieldsForm>(context);
return Theme(
data: Theme.of(context).copyWith(
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
),
),
),
child: SafeArea(
child: Scaffold(
body: FormBlocListener<ConditionalFieldsForm, String,
String>(
onSubmitting: {
...
},
onSubmissionFailed: (context, state) {
LoadingDialog.hide(context);
},
onSuccess: (context, state) {
LoadingDialog.hide(context);
},
onFailure: (context, state) {
LoadingDialog.hide(context);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(state.failureResponse!)));
},
child: SingleChildScrollView(
physics: const ClampingScrollPhysics(),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
...
),
ElevatedButton(
onPressed: formBloc.submit,
child: Text('SUBMIT'),
),
],
),
),
),
),
),
),
);
},
),
)),
);
}
}
class LoadingDialog extends StatelessWidget {
...
}
class ConditionalFieldsForm extends FormBloc<String, String> {
static final roles = SelectFieldBloc(
validators: [FieldBlocValidators.required],
items: ['Trainee', 'Employer', 'Department'],
);
static final TraineeEmail = TextFieldBloc(
validators: [FieldBlocValidators.required, FieldBlocValidators.email],
);
...
ConditionalFieldsForm() {
addFieldBlocs(
fieldBlocs: [
roles,
],
);
...
#override
Future<void> close() {
TraineeEmail.close();
TraineePassword.close();
TraineeConfirmPassword.close();
TraineeDOB.close();
TraineePhoneNumber.close();
TraineeSkills.close();
TraineeNationality.close();
TraineeAddress.close();
TraineeCurrentInstituation.close();
TraineeMajor.close();
TraineeName.close();
TraineeGender.close();
EmployerPhoneNumber.close();
EmployerWebsite.close();
EmployerPassword.close();
EmployerEmail.close();
EmployerAddressID.close();
EmployerDescription.close();
EmployerName.close();
DepartmentPhoneNumber.close();
DepartmentPassword.close();
DepartmentEmail.close();
DepartmentAddressID.close();
DepartmentCategory.close();
DepartmentName.close();
roles.close();
terms.close();
traineeRegistred.close();
employerRegistred.close();
return super.close();
}
#override
onSubmitting() async {
}
}
The problem is when I navigate from login to list registration page then back to login page and try to back again to list registration page I got this error:
error message screen
I tried to use dispose and change login screen from state less to state full but that didn't work with me.

How can I show overlay on top of the whole app in flutter?

I want to show an overlay on the whole app so I tried to insert an overlay entry on the context of MaterialApp (root widget) but the problem is I'm getting the null value on invoking the following method :
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();
},
));
}
Is there any way to get the state of overlay using the context of this root widget as I want to show the overlay globally.
Thanks alot, I really appreciate that If someone helps me.
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,
),
You can achieve that by create a class responsible to display/remove the overlay, this class need receive a BuildContext when creating to be able to create an instance of Overlay.
Basically what you need to do are:
Create a class OverlayScreen that build the OverlayState && OverlayEntry (in this case the OverylayEntry will be a list of OverlayEntry since we might have more than one Overlay on the screen so we can remove all of them at once).
Create an instance of this class earlier in your app (e.g MyApp). In your case you'll need to call this inside Material.router...builder param.
Access this overlayScreen in your HomePage to display|removeAll overlays
Lets create our 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"),
),
);
}
}
Now lets create an instance on 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();
},
),
],
);
},
);
}
}
To finalise lets create our HomePage and access our overlayScreen there there
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'),
),
],
),
),
);
}
}
That's it. You can use this class OverlayScreen to show/removeAll wherever you want.
I created a PR with sample code, check it out 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(),
),
),
),
);
}
}

Flutter build not behaving as expected

I'm trying to make a note app but there is a yellow square showing on the screen.
I've included the main.dart code and also allnotesscreens.dart. I think there is something wrong with allnotesscreens code, but I don't know what.
Maybe _loadViewMode() part.
Why this problem is happening?!!!
Main.dart:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'providers/label_provider.dart';
import 'providers/note_provider.dart';
import 'package:provider/provider.dart';
import 'constants/app_constants.dart';
import 'screens/all_labels_screen.dart';
import 'screens/all_notes_screen.dart';
import 'screens/drawer_screen.dart';
main() {
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
systemNavigationBarColor: ColorsConstant.grayColor,
),
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => NoteProvider()),
ChangeNotifierProvider(create: (_) => LabelProvider()),
],
builder: (context, child) => MaterialApp(
title: 'Note-App',
debugShowCheckedModeBanner: false,
themeMode: ThemeMode.dark,
theme: customThemeData(context),
initialRoute: '/',
routes: {
'/': (context) => const AllNotesScreen(),
DrawerScreen.routeName: (context) => const DrawerScreen(),
AllLabelsScreen.routeName: (context) => const AllLabelsScreen(),
},
),
);
}
}
allnotesscreens.dart:
class AllNotesScreen extends StatefulWidget {
const AllNotesScreen({Key? key}) : super(key: key);
#override
State<AllNotesScreen> createState() => _AllNotesScreenState();
}
class _AllNotesScreenState extends State<AllNotesScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child:
Container(
height: 200,
width: 100,
color: Colors.yellow,
),
),
);
}
String _viewMode = ViewMode.staggeredGrid.name;
bool _isLoading = false;
final _scaffoldKey = GlobalKey<ScaffoldState>();
#override
void initState() {
super.initState();
setState(() {
_isLoading = true;
});
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
Future _loadViewMode() async {
final prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey('view-mode')) return;
setState(() {
_viewMode = prefs.getString('view-mode') ?? ViewMode.staggeredGrid.name;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: const Text(
"all notes",
style: TextStyleConstants.titleAppBarStyle,
),
actions: [
if (context
.watch<NoteProvider>()
.items
.isNotEmpty)
IconButton(
onPressed: () {
showSearch(
context: context,
delegate: NoteSearch(isNoteByLabel: false),
);
},
icon: const Icon(Icons.search),
),
IconButton(
onPressed: () async {
final result = await changeViewMode(_viewMode);
setState(() {
_viewMode = result;
});
},
icon: _viewMode == ViewMode.staggeredGrid.name
? const Icon(Icons.view_stream)
: const Icon(Icons.grid_view),
),
const SizedBox(
width: 6,
)
],
),
drawer: const DrawerScreen(),
body: _isLoading
? const Center(
child: CircularProgressIndicator(),
)
: RefreshIndicator(
onRefresh: () => refreshOrGetData(context),
child: Consumer<NoteProvider>(
builder: (context, noteProvider, child) =>
noteProvider.items.isNotEmpty
? NoteListViewWidget(
notes: noteProvider.items,
viewMode: _viewMode,
scaffoldContext: _scaffoldKey.currentContext!,
)
: child!,
child: const NoNoteUIWidget(
title: "your notes after adding will appear here",
),
),
),
floatingActionButton: FloatingActionButton(
child: linearGradientIconAdd,
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => const EditNoteScreen(),
));
},
),
);
}
}
}
The first few lines of your _AllNotesScreenState class are why there's a yellow square; that's what you're telling it to build.
class _AllNotesScreenState extends State<AllNotesScreen> {
// this build function here is what is drawing to the screen
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child:
Container(
height: 200,
width: 100,
color: Colors.yellow,
),
),
);
}
Maybe it's just how you've pasted it in, but it appears as though you have a build function defined within the didChangeDependencies function. If you took it out of there, it would then make it apparent that you have two build functions defined for the class.
I'm assuming it's the second one that you actually want building.
#override
void didChangeDependencies() {
super.didChangeDependencies();
Future _loadViewMode() async {
final prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey('view-mode')) return;
setState(() {
_viewMode = prefs.getString('view-mode') ?? ViewMode.staggeredGrid.name;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
...

How to implement telegram style pop up in flutter? [duplicate]

I want a widget that will sit on top of the entire application. When I have tried to do this with Overlay.of(context).insert the overlay would later disappear after replacing that route. Is there a way I can have a widget on top of my app even if the screen is later popped?
Maybe a more optimal way exists, but as an option this is an example with two pages, local navigator and Overlay.
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'),
),
);
}
}
Screenshot (Null safe):
Full code:
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Offset _offset = Offset.zero;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: LoginPage(),
builder: (context, child) {
return Stack(
children: [
child!,
Positioned(
left: _offset.dx,
top: _offset.dy,
child: GestureDetector(
onPanUpdate: (d) => setState(() => _offset += Offset(d.delta.dx, d.delta.dy)),
child: FloatingActionButton(
onPressed: () {},
backgroundColor: Colors.black,
child: Icon(Icons.add),
),
),
),
],
);
},
);
}
}
LoginPage:
class LoginPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('LoginPage')),
body: Center(
child: ElevatedButton(
onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (_) => HomePage())),
child: Text('Page2'),
),
),
);
}
}
HomePage:
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('HomePage')),
body: FlutterLogo(size: 300),
);
}
}
After reading the comments, find github-repo-link
created an overlay that will sit on top of everything
that can be called from anywhere.
just 4 easy steps to follow
flutterflutter-layout
STEP-1: in main.dart:
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
],
),
);
}
}
STEP-2: OverLayView.dart
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();
}
},
);
}
STEP-3: loder_controller.dart (to show/hide)
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 //
}
}
FINAL STEP-4: show/hide loder
I'm showing it, on boilerplate code of increment method to show the loader
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
}
As a supplement to other answers: If you want to show some overlays, the flutter_portal may indeed be a better choice that is simpler to use.
Basically, it looks like:
PortalTarget(
// Declarative
portalFollower: MyAwesomeOverlayWidget(),
// Align anywhere you like. Now `portalFollower` floats at right of `child`
anchor: const Aligned(follower: Alignment.topLeft, target: Alignment.topRight),
child: MyChildWidget(),
)
Notice that it is declarative (not imperative as opposed to Overlay). Moreover, you get the bonus that the alignment is very easy, and the context is intuitive.
Disclaimer: I am the current owner of this library.
Have you tried to add a Navigator as a child/descendant of your Scaffold? As far as I remember, the default navigator is in the MaterialApp, which is above everything. When you add your own Navigator, your routing will happen under the Scaffold rather than above it in the tree.

Flutter carousel image slider open separate page during on tap

I am looking forward to open image on clicking specific image. I am just able to open the first image on clicking it. I am not able to open other image I want to open image which is clicked. How can I have a separate page for different image click. For example, I have five image in my flutter carousel slider. Image 1 will open sliderpage 1. Image 2 will open sliderpage 2 and so on
import 'package:flutter/material.dart';
import 'package:carousel_slider/carousel_slider.dart';
import './screen.dart';
void main() => runApp(MaterialApp(home: Demo()));
class Demo extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<Demo> {
#override
Widget build(BuildContext context) {
Widget image_carousel = new Container(
height: 345.0,
child: CarouselSlider(
height: 400.0,
items: [
'http://pic3.16pic.com/00/55/42/16pic_5542988_b.jpg',
'http://photo.16pic.com/00/38/88/16pic_3888084_b.jpg',
'http://pic3.16pic.com/00/55/42/16pic_5542988_b.jpg',
'http://photo.16pic.com/00/38/88/16pic_3888084_b.jpg'
].map((i) {
return Builder(
builder: (BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.symmetric(horizontal: 5.0),
decoration: BoxDecoration(color: Colors.amber),
child: GestureDetector(
child: Image.network(i, fit: BoxFit.fill),
onTap: () {
Navigator.push<Widget>(
context,
MaterialPageRoute(
builder: (context) => ImageScreen(i),
),
);
}));
},
);
}).toList(),
));
return Scaffold(
body: new Column(
children: <Widget>[
image_carousel,
],
),
);
}
}
Next page called screen.dart
import 'package:flutter/material.dart';
class ImageScreen extends StatefulWidget {
final String url;
ImageScreen(this.url);
#override
_MyImageScreen createState() => _MyImageScreen(url);
}
class _MyImageScreen extends State<ImageScreen> {
final String url;
_MyImageScreen(this.url);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ImageScreen'),
),
body: Image.network(url, width: double.infinity));
}
}
You can copy paste run full code below
You can use route and Navigator.pushNamed to pass argument
code snippet
routes: {
'/': (context) => Demo(),
'/first': (context) => FirstScreen(),
'/second': (context) => SecondScreen(),
});
...
items: [
{
"url": 'https://pic3.16pic.com/00/55/42/16pic_5542988_b.jpg',
"routeName": "/first"
},
...
Widget build(BuildContext context) {
final Map args = ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: AppBar(
title: Text('First Screen'),
),
body: Image.network(args["url"], width: double.infinity));
working demo
full code
import 'package:flutter/material.dart';
import 'package:carousel_slider/carousel_slider.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: Demo(),
initialRoute: '/',
routes: {
'/': (context) => Demo(),
'/first': (context) => FirstScreen(),
'/second': (context) => SecondScreen(),
});
}
}
class Demo extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<Demo> {
#override
Widget build(BuildContext context) {
Widget image_carousel = new Container(
height: 345.0,
child: CarouselSlider(
height: 400.0,
items: [
{
"url": 'https://pic3.16pic.com/00/55/42/16pic_5542988_b.jpg',
"routeName": "/first"
},
{
"url": 'https://photo.16pic.com/00/38/88/16pic_3888084_b.jpg',
"routeName": "/second"
},
{
"url": 'https://pic3.16pic.com/00/55/42/16pic_5542988_b.jpg',
"routeName": "/first"
},
{
"url": 'https://photo.16pic.com/00/38/88/16pic_3888084_b.jpg',
"routeName": "/second"
},
].map((i) {
return Builder(
builder: (BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.symmetric(horizontal: 5.0),
decoration: BoxDecoration(color: Colors.amber),
child: GestureDetector(
child: Image.network(i["url"], fit: BoxFit.fill),
onTap: () {
print('i $i');
Navigator.pushNamed(
context,
i["routeName"],
arguments: i,
);
}));
},
);
}).toList(),
));
return Scaffold(
body: new Column(
children: <Widget>[
image_carousel,
],
),
);
}
}
class SecondScreen extends StatefulWidget {
#override
_SecondScreenState createState() => _SecondScreenState();
}
class _SecondScreenState extends State<SecondScreen> {
#override
Widget build(BuildContext context) {
final Map args = ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: AppBar(
title: Text('Second Screen'),
),
body: Image.network(args["url"], width: double.infinity));
}
}
class FirstScreen extends StatefulWidget {
#override
_FirstScreenState createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
#override
Widget build(BuildContext context) {
final Map args = ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: AppBar(
title: Text('First Screen'),
),
body: Image.network(args["url"], width: double.infinity));
}
}