i want wait 5 seconds on main page and display loading animation then navigate to another page.
here is my code
import 'mainPage.dart';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'dart:async';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool isLoading = true;
#override
void initState() {
super.initState();
loadData();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Colors.cyan,
body: Builder(
builder: (context) => Center(
child: Container(
child: SpinKitCubeGrid(color: Colors.white, size: 50.0),
),
),
),
),
);
}
Future loadData() async {
return new Timer(Duration(seconds: 5), () {
setState(() {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => MainPage()));
});
});
}
}
but i got this error:
Unhandled Exception: Navigator operation requested with a context that does not include a Navigator.
what should i do?
Wrap MyApp with MaterialApp which will provide the right context to Navigator
void main() {
runApp(MaterialApp(home: MyApp()));
}
Maybe this will help U
static Route route() {
return MaterialPageRoute<void>(builder: (_) => MyApp());
}
onPressed: () => Navigator.of(context).push<void>(MainPage.route()),
................
static Route route() {
return MaterialPageRoute<void>(builder: (_) => MainPage());
}
onPressed: () => Navigator.of(context).push<void>(MyApp.route()),
Can you try it like this? I didn't run the code but showing the basic idea. Just pass the context and call it from build function.
class _MyAppState extends State<MyApp> {
bool isLoading = true;
#override
Widget build(BuildContext context) {
loadData(context);
return MaterialApp(
...
);
}
Future loadData(context) async {
...
}
}
You need a context to navigate with the Navigator.
To navigate without using context you can use a package called GetX
Example:
Add "Get" before your MaterialApp, turning it into GetMaterialApp
GetMaterialApp( // Before: MaterialApp(
home: MyHome(),
)
Navigate to a new screen:
Get.to(NextScreen());
Related
Please help.
I'm trying to display the photo captured in 'Generated1Group1Widget1.dart' to 'GeneratedResultsWidget.dart'. However, 'main.dart' is having some errors.
GeneratedGroup1Widget1.dart
class GeneratedGroup1Widget1 extends StatefulWidget {
#override
_GeneratedGroup1Widget1State createState() => _GeneratedGroup1Widget1State();
}
class _GeneratedGroup1Widget1State extends State<GeneratedGroup1Widget1> {
XFile? _image;
Future _pickImage() async {
final imageSource = await showDialog<ImageSource>(
context: context,
builder: (context) => SimpleDialog(
title: const Text('Select Image Source'),
children: [
SimpleDialogOption(
onPressed: () => Navigator.pop(context, ImageSource.camera),
child: const Text('Camera'),
),
SimpleDialogOption(
onPressed: () => Navigator.pop(context, ImageSource.gallery),
child: const Text('Gallery'),
),
],
),
);
if (imageSource != null) {
final image = await ImagePicker().pickImage(source: imageSource);
setState(() {
_image = image;
});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => GeneratedResultsWidget(image: _image),
),
);
}
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => _pickImage(),
...
GeneratedResultsWidget.dart
class GeneratedResultsWidget extends StatelessWidget {
final XFile? image;
GeneratedResultsWidget({
required this.image,
});
#override
Widget build(BuildContext context) {
return Material(
child: ClipRRect(
...
main.dart
void main() {
runApp(food_classifierApp());
}
class food_classifierApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: Size(360, 640),
builder: (BuildContext context,child) => MaterialApp(
title: 'food-classifier',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: '/GeneratedHomepageWidget',
routes: {
'/GeneratedScanWidget': (context) => GeneratedScanWidget(),
'/GeneratedResultsWidget': (context) => GeneratedResultsWidget(image: _image),
'/GeneratedHomepageWidget': (context) => GeneratedHomepageWidget(),
'/GeneratedFoodlistWidget': (context) => GeneratedFoodlistWidget(),
},
),
);
}
}
Error
Undefined name '_image'.
Try correcting the name to one that is defined, or defining the name.
I already searched up google but I can't find answers to my question. Thanks in advance!
Where exactly you define _image variable in your food_classifierApp class?
You should use state management to access your image or ... in every where of your app
You need to create model to store your picked image file from GeneratedGroup1Widget1.
class AppModel {
String fileName;
AppModel(this.fileName);
}
Now you can call it from GeneratedGroup1Widget1
Navigator.pushNamed(context, '/GeneratedResultsWidget',
arguments: AppModel('your file or file name'));
And recieve it here
class GeneratedResultsWidget extends StatelessWidget {
const GeneratedResultsWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final args = ModalRoute.of(context)!.settings.arguments as AppModel;
return Scaffold(body: Center(child: Text(args.fileName)));
}
}
Route should be
routes: {
//***
'/GeneratedResultsWidget': (context) => GeneratedResultsWidget(),
//***
}
I'm trying to implement the camera package in flutter for android and iOS devices,
On android I don't have any problem but in iOS i get this error:
The following StateError was thrown building Builder:
Bad state: No element
When the exception was thrown, this was the stack:
#0 List.first (dart:core-patch/growable_array.dart:332:5)
#1 _CameraState.initState (package:glass_case_flutter/controllers/camera_controller.dart:21:45)
#2 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4632:57)
#3 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4469:5)
... Normal element mounting (24 frames)
this is the code of main.dart:
List<CameraDescription> cameras;
Future<Null> main() async {
WidgetsFlutterBinding.ensureInitialized();
cameras = await availableCameras();
await Firebase.initializeApp();
runApp(GlassCase());
}
class GlassCase extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(fontFamily: 'Nunito'),
initialRoute: WelcomeScreen.id,
routes: {
WelcomeScreen.id: (context) => WelcomeScreen(),
RegistrationScreen.id: (context) => RegistrationScreen(),
ResetPassword.id: (context) => ResetPassword(),
HomeScreen.id: (context) => HomeScreen(cameras),
ProfileScreen.id: (context) => ProfileScreen()
},
);
}
}
this is the code of my homepage.dart where I call camera.dart:
IconButton(
icon: Icon(Icons.camera_alt),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Camera(widget.cameras)));
},
color: Colors.black,
),
this is my camera.dart, that is very simple, just turn on the camera:
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
class Camera extends StatefulWidget {
List<CameraDescription> cameras;
Camera(this.cameras);
#override
_CameraState createState() => _CameraState();
}
class _CameraState extends State<Camera> {
CameraController controller;
#override
void initState() {
super.initState();
controller =
new CameraController(widget.cameras.first, ResolutionPreset.high);
controller.initialize().then((_) {
if (!mounted) {
return;
}
setState(() {});
});
}
#override
void dispose() {
controller?.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
if (!controller.value.isInitialized) {
return new Container();
}
return new AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: CameraPreview(controller),
);
}
}
I added this in my Info.plist to access the camera and microphone:
<key>NSCameraUsageDescription</key>
<string>Enable to access your camera to capture your photo</string>
<key>NSMicrophoneUsageDescription</key>
<string>Enable to access mic to record your voice</string>
I don't understand why in Android it work but in iOS I get that error, somebody can help me ?
Thank so much !
I'm having a problem with my app.
The situation is: i have a very simple login system on the app and i save the logged user using SharedPreferences.
But if the user leaves the app and then return it will open the login screen again, so i want to skip the login screen if the user is logged.
So in my main i put a function to check if there is login information, if yes it would redirect right to the app page or to the login page if not.
But when i try to call the app page it always calls the page setted on the Home part.
How can i solve this?
Is there any way to make it ignore the Home?
Is there a way to make the "if" part on the home? Would be the better solution but its not possible.
Also i know i'm not using the best way to make this control, but it works (despite of this problem i have now, sure) and if you have any tips on making it better i would appreciate.
Heres my code:
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
void main() => runApp(new MyApp());
class _MyAppState extends State<MyApp> {
Future<void> verificaLogin() async {
print("running ok"); //just to test if the function runs
final prefs = await SharedPreferences.getInstance();
final key = 'usuario';
final value = prefs.getString(key);
print('saved tester $value');
String usu = value; /
if (usu.isEmpty) {
BuildContext context;
Navigator.push(
context,
MaterialPageRoute(builder: (context) => LoginScreen()), //sends to loginscreen if not logged
);
}
if (usu.isNotEmpty) {
BuildContext context;
Navigator.of(context)
.pushReplacement(MaterialPageRoute(builder: (context) => Pedidos())); //sends to main (not main.dart) app page
}
}
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) => verificaLogin());
}
Widget build(BuildContext context) {
return BotToastInit(
child: MaterialApp(
navigatorObservers: [BotToastNavigatorObserver()],
title: "Test App",
theme: ThemeData(
primarySwatch: Colors.green,
),
debugShowCheckedModeBanner: false,
home: LoginScreen(), //i'm calling the loginscreen, it ignores the function on the top
),
);
}
}
Please make one SplashScreen like below it resolves your issue..
and call this as home: SplashScreen(),
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
String loginData = "";
SharedPreferences sharedPreferences;
void initState() {
super.initState();
readFromStorage();
}
void readFromStorage() async {
sharedPreferences = await SharedPreferences.getInstance();
final key = 'usuario';
loginData = sharedPreferences.getString(key);
if (loginData.isNotEmpty) {
Future.delayed(const Duration(milliseconds: 3000), () {
setState(() {
Navigator.of(context)
.pushReplacement(MaterialPageRoute(builder: (context) => Pedidos()));
});
});
} else {
Future.delayed(const Duration(milliseconds: 3000), () {
setState(() {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => LoginScreen()),);
});
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FlutterLogo(
size: 100.0,
),
],
)),
);
}
}
Hi you can use a FutureBuilder at vefiricaLoigin, and then Material App at home use verificaLogin,
https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html
verificaLogin() {
return FutureBuilder<Widget>(
future: SharedPreferences.getInstance(),
builder: (BuildContext context, prefs) {
final key = 'usuario';
final value = prefs.getString(key);
String usu = value;
if (usu.isEmpty) {
return LoginScreen()l
} else {
return Pedidos();
}
);
}
Widget build(BuildContext context) {
return MaterialApp(
title: "Test App",
theme: ThemeData(
primarySwatch: Colors.green,
),
debugShowCheckedModeBanner: false,
home: verificaLogin()
);
}
I'm building android app using flutter. I have a problem to close the simple dialog programmatically.
Now I have a stateful page named ListVessel. This page contains listTile from array otherVessels.
Below is the code for this page.
class ListVessel extends StatefulWidget {
final Function() notifyParent;
ListVessel({Key key, #required this.notifyParent}) : super(key: key);
#override
_ListVesselState createState() => _ListVesselState();
}
class _ListVesselState extends State<ListVessel> {
#override
Widget build(BuildContext context) {
return ListView.separated(
separatorBuilder: (context, index) => Divider(color: Colors.blueGrey),
itemCount: otherVessels.length,
itemBuilder: (context, index) {
return ListTile(
title: Text("Name: "+otherVessels[index]["shipName"]),
onTap: () {
showDialog (
context: context,
builder: (_){
return otherTap(idx:index);
}
);
}
);
},
);
}
}
}
From above code, each tile (vessel) can be tapped and it calls otherTap() method. otherTap() method displays a simple dialog (popup) that contains the details of the tapped vessel.
Below is the code for otherTap().
class otherTap extends StatefulWidget{
otherTap({Key key, #required this.idx}) : super(key: key);
final int idx;
#override
_otherTapState createState() => new _otherTapState();
}
class _otherTapState extends State<otherTap>{
#override
Widget build(BuildContext context){
_isDialogShowing = true;
return SimpleDialog(
title: Text(otherVessels[widget.idx]["shipName"]),
children: <Widget>[
SimpleDialogOption(
child: Text('MMSI : ' + otherVessels[widget.idx]['MMSI']),
)
],
);
}
}
I have a global boolean variable (_isDialogShowing) to keep tracking if the dialog is showing.
Now i want the showdialog (popup) to dismiss after 5 second.
I use Navigator.pop() to dismiss the dialog in the MyApp function. I put it inside setstate() function.
void main() {
runApp(
MyApp(storage: CounterStorage()),
);
}
class MyApp extends StatefulWidget {
MyApp({Key key, #required this.storage}) : super(key: key);
final CounterStorage storage;
#override
State<StatefulWidget> createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
final appTitle = 'Testing applicatin';
void _update(BuildContext context) async {
await Future.delayed(Duration(milliseconds: 5000));
setState(() {
if(_isDialogShowing){
_isDialogShowing = false;
Navigator.pop(context);
//Navigator.of(context).pop();
}
});
}
#override
Widget build(BuildContext context) {
_update(context);
return new WillPopScope(
onWillPop: null,
child: new MaterialApp(
debugShowCheckedModeBanner: false,
title: appTitle,
home: MyHomePage(title: appTitle),
routes: {
Routes.home: (context) => MyHomePage(),
Routes.settings: (context) => SettingsPage(),
},
),
);
}
}
However the navigator.pop methods above doesn't close the popup.
Can anyone help?
You need to call pop on the context that you receive in builder of showDialog(), only then the dialog will pop that was created by that showDialog().
Replace your showDialog() with following and it will work for you:
showDialog(
context: context,
builder: (BuildContext context) {
Future.delayed(Duration(seconds: 5)).then((_) {
Navigator.pop(context);
});
return otherTap(idx:index);
},
);
I've solved this issue using
Navigator.of(context, rootNavigator: true).pop();
In the app, on starting splash screen appears after that I reach to the login screen where there is no app bar or back button but I'm able to back from device back button. I don't want to back on the splash screen when the back is pressed from login screen. I tried many solutions but they are not working.
class Login extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'xyz',
home: LoginPage(),
debugShowCheckedModeBanner: false,
);
}
}
class LoginPage extends StatefulWidget {
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
if (Navigator.canPop(context)) {
Navigator.pop(context); // i tried both the way
Navigator.of(context).pop();
} else {
SystemNavigator.pop();
}
},
child:Scaffold(
body: Container(.........................//here is my desiging stuff
I also tried return Future.value(false); with true and false value –
Splash screen code
#override
void initState (){
super.initState();
// TODO initial state stuff
new Future.delayed(
const Duration(seconds: 2),
() => Navigator.push(
context,
MaterialPageRoute(builder: (context) => Login()),
));
}
Simply pass empty function to - WillPopScope widget.
class LoginPage extends StatefulWidget {
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {}, // Empty Function.
child: Scaffold(
body: Container(), //here is my desiging stuff
));
}
}
OR
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
return false;
},
child: Scaffold(
body: Container(),
appBar: AppBar(),
),
);
}
If you never want to goto Splash Screen.
It's Better to use:
Navigator.of(context)
.pushReplacement(MaterialPageRoute(builder: (context) => Login()));
Just change your code to:
class _LoginPageState extends State<LoginPage> {
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: ()async => false,
child:Scaffold(
body: Container(.........................//here is my desiging stuff
I had the same problem, and it was because wrongly surrounding MaterialApp with WillPopScope (instead of surrounding Scaffold).
Appreciating #anmol-majhail, here is the correct solution in my case:
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
home: WillPopScope(
child: Scaffold(...),
onWillPop: () async {
return false;
}),
);
}