Flutter navigator hides (covers) first window conent - flutter

Why when I use the navigator to go to another page(widget) that covers just part of the screen, I can't see the first-page content (which is on top of the page)?
I tried code from this example (https://docs.flutter.dev/cookbook/navigation/navigation-basics) and modified it a little to show what I need:
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(
title: 'Navigation Basics',
home: FirstRoute(),
));
}
class FirstRoute extends StatelessWidget {
const FirstRoute({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('First Route'),
),
body: Center(
child: ElevatedButton(
child: const Text('Open route'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SecondRoute()),
);
},
),
),
);
}
}
class SecondRoute extends StatelessWidget {
const SecondRoute({super.key});
#override
Widget build(BuildContext context) {
return Container(
padding:const EdgeInsets.only(top:128),
color:Colors.transparent,
child: Scaffold(
appBar: AppBar(
title: const Text('Second Route'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Go back!'),
),
),
),
);
}
}

You can achieve this using bottom sheet.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
// Remove the debug banner
debugShowCheckedModeBanner: false,
title: 'example',
home: HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
void _show(BuildContext ctx) {
showModalBottomSheet(
elevation: 10,
isScrollControlled: true,
context: ctx,
builder: (ctx) => Container(
//change height to change height of bottom sheet
height: MediaQuery.of(ctx).size.height * 0.75,
alignment: Alignment.center,
child: const Text('bottom sheet'),
));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Example'),
),
body: SafeArea(
child: Center(
child: ElevatedButton(
child: const Text('Show The BottomSheet'),
onPressed: () => _show(context),
),
),
),
);
}
}

use this class instead of your class
class SecondRoute extends StatelessWidget {
const SecondRoute({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Second Route'),
),
body: Container(
padding:const EdgeInsets.only(top:128),
child: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Go back!'),
),
),
),
);
}
}

Related

Managing routing and state from a central place in flutter

I have this simple flutter app that consists of just two pages linked with the router which is defined in the main() function. However, i would like to isolate my classes into their own files since my app consists of many pages. Here is my code
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
title: 'Named Routes',
initialRoute: '/',
routes: {
'/': (context) => const firstRoute(),
'/second': (context) => const secondRoute(),
},
));
}
// ignore: camel_case_types
class firstRoute extends StatelessWidget {
const firstRoute({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('GFG First Route'),
backgroundColor: Colors.green,
),
body: Center(
child: ElevatedButton(
child: const Text('Launch screen'),
onPressed: () {
Navigator.pushNamed(context, '/second');
},
), // Elevated
// RaisedButton is deprecated now
// child: RaisedButton(
// child: const Text('Launch screen'),
// onPressed: () {
// Navigator.pushNamed(context, '/second');
// },
// ),
),
);
}
}
// ignore: camel_case_types
class secondRoute extends StatelessWidget {
const secondRoute({Key? key}) : super(key: key);
#override
// ignore: dead_code
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("GFG Second Route"),
backgroundColor: Colors.green,
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Go back!'),
), // ElevatedButton
),
// RaisedButton is deprecated now
// child: RaisedButton(
// onPressed: () {
// Navigator.pop(context);
// },
// child: const Text('Go back!'),
// ),
);
}
}
How would i go about isolating each of my classes in separate .dart files and still make use of the routing defined in main?
Also, i would like to have some global state accessible in each of the dart files i shall create. How would i go about solving the first and second problems?.
you can separate your current code into 3 files.
1: main.dart
import 'package:flutter/material.dart';
import 'package:<app_name>/screens/firstRoute.dart';
import 'package:<app_name>/screens/secondRoute.dart';
// this is a globally available variable
final valueNotifier = ValueNotifier('hello');
void main() {
runApp(MaterialApp(
title: 'Named Routes',
initialRoute: '/',
routes: {
'/': (context) => const firstRoute(),
'/second': (context) => const secondRoute(),
},
));
}
2: firstFile.dart
class firstRoute extends StatelessWidget {
const firstRoute({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('GFG First Route'),
backgroundColor: Colors.green,
),
body: Center(
child: ElevatedButton(
child: const Text('Launch screen'),
onPressed: () {
Navigator.pushNamed(context, '/second');
},
),
),
);
}
}
3: secondFile.dart
// imported main.dart so that we can use valueNotifier
import 'package:<app_name>/main.dart';
import 'package:flutter/material.dart';
class secondRoute extends StatelessWidget {
secondRoute({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("GFG Second Route"),
backgroundColor: Colors.green,
),
body: Column(children: [
ValueListenableBuilder(
valueListenable: valueNotifier,
builder: ((BuildContext context, String updatedValue, Widget? child) {
return Text(updatedValue);
}),
),
Center(
child: ElevatedButton(
onPressed: () {
valueNotifier.value = 'got changed';
},
child: const Text('Change me'),
), // ElevatedButton
),
]),
);
}
}
once you've separated the files, you'll need to import them... say, you've created the files in lib/screens
so, the import line will be something like this, vs code/Android Studio can take care of it
import 'package:<app_name>/screens/secondRoute.dart';
for global state management, you can have a ValueNotifier which is globally exposed from main.dart you can simply listen to its change via ValueListenableBuilder a very basic implementation is shown as well
although this is not recommended for bigger projects, if that's the case then you should use something like provider

Flutter: Adding button shows up behind ListView, "duplicate child" error

I'm trying to add a button to navigate to another screen but I'm not sure how to get it on the bottom of my list instead of behind it. This is my current list:
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.teal[800],
appBar: AppBar(
title: Text(widget.title),
),
body: SafeArea(
child: ListView.builder(
itemCount: Type.samples.length,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return BoardingDetail(boarding: Type.samples[index]);
},
),
);
},
child: buildBoardingCard(Type.samples[index]),
);
},
),
),
);
}
And I think this is the code I want to add to navigate to a new screen, I got this code from https://docs.flutter.dev/cookbook/navigation/navigation-basics
child: ElevatedButton(
child: const Text('Open route'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SecondRoute()),
);
},
),
I tried to integrate the navigation button into my code but it says I have "duplicate child". What is the proper way to do this?
You have to nest the ListView and ElevatedButton in a SingleChildScrollView with a Column
You can try running this to see how it is implemented:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "ListView.builder",
theme: ThemeData(primarySwatch: Colors.green),
debugShowCheckedModeBanner: false,
home: const ListViewBuilder());
}
}
class ListViewBuilder extends StatelessWidget {
const ListViewBuilder({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("ListView.builder")),
body: SingleChildScrollView(
child: Column(
children: [
ListView.builder(
shrinkWrap: true,
itemCount: 8,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: const Icon(Icons.list),
trailing: const Text(
"GFG",
style: TextStyle(color: Colors.green, fontSize: 15),
),
title: Text("List item $index"));
},
),
ElevatedButton(
child: const Text('Open route'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SecondRoute()),
);
},
),
],
),
),
);
}
}
class SecondRoute extends StatelessWidget {
const SecondRoute({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Second Route'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
// Navigate back to first route when tapped.
},
child: const Text('Go back!'),
),
),
);
}
}

Unable to navigate from GetX Dialog to another screen

I have follow dialog box. When I click 'Next' I want it to navigate to GamePage() screen. But unfortunately it doesn't work.
Following is the GamePage Widget
class GamePage extends StatelessWidget {
final homeCtrl = Get.find<HomeController>();
GamePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF8fb1ca),
body: SafeArea(
child: ListView(
children: [
Padding(
padding: EdgeInsets.all(3.0.wp),
child: Row(
children: [
IconButton(
onPressed: () {
Get.back();
},
icon: const Icon(Icons.arrow_back),
),
],
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 4.0.wp),
child: Column(
children: [
SizedBox(
height: 2.0.wp,
),
Center(
child: Text(
'What ${homeCtrl.currentWord.first.wordtype} is this?',
style: TextStyle(
fontSize: 18.0.sp,
color: Colors.grey[800],
),
),
),
SizedBox(height: 10.0.wp),
WordsWidget(currentWord: homeCtrl.currentWord.first),
],
),
),
],
),
),
);
}
}
Following is the Word Widget being called from GamePage Widget
class WordsWidget extends StatelessWidget {
final currentWord;
WordsWidget({Key? key, this.currentWord}) : super(key: key);
final homeCtrl = Get.find<HomeController>();
#override
Widget build(BuildContext context) {
// var currentWord = homeCtrl.nextWord();
var shuffleword = [].obs;
shuffleword.addAll(homeCtrl.shuffleWord(currentWord.word));
TextToSpeech tts = TextToSpeech();
String language = 'en-US';
tts.setLanguage(language);
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
print('pressed here');
Get.defaultDialog(
title: 'Go to next page',
content: Container(
child: Column(
children: [
Text('You are about to move to another screen'),
ElevatedButton.icon(
onPressed: () {
Get.to(() => GamePage());
},
icon: Icon(
Icons.arrow_right,
),
label: Text('Go'))
],
),
));
},
child: Text('Open Dialog')),
],
);
}
}
Get.back() is working but not Get.to
Try
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) {
return const GamePage();
},
),
);
},
child: Text("Next Word"),
)
Try this code -
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:image_memory/next_page.dart';
import 'package:image_picker/image_picker.dart';
void main() {
//check getMaterialApp is used
runApp(const GetMaterialApp(
title: 'Temp',
home: const MyApp(),
));
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Image Picker'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
print('pressed here');
Get.defaultDialog(
title: 'Go to next page',
content: Container(
child: Column(
children: [
Text('You are about to move to another screen'),
ElevatedButton.icon(
onPressed: () {
Get.to(() => NextPage());
},
icon: Icon(
Icons.arrow_right,
),
label: Text('Go'))
],
),
));
},
child: Text('Open Dialog')),
),
);
}
}
and next page is -
import 'package:flutter/material.dart';
class NextPage extends StatefulWidget {
const NextPage({ Key? key }) : super(key: key);
#override
State<NextPage> createState() => _NextPageState();
}
class _NextPageState extends State<NextPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Next Page'),
),
body: Container(
child: Center(
child: Text("this is next page"),
),
),
);
}
}
And yes, you need to insure that you are using 'GetMaterialApp'.
If you want to use GetX navigation system, you should wrap your application in a GetMaterialApp instead of MaterialApp.
So in your main use this:
class GetxApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GetMaterialApp(
home: HomePage(),
);
}
}
Instead of this:
class NormalApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}

Flutter navigator not working : OnPress not showing second screen

This is my code don't know why its not moving to screen 2 on button press:
Am beginner in dart/flutter please help. On press of button it's not showing screen2
//main.dart
import 'package:flutter/material.dart';
import 'screen_1.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Screen1(),
);
}
}
//screen_1.dart
import 'package:flutter/material.dart';
import 'screen_2.dart';
class Screen1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Screen 1'),
),
body: Container(
child: Center(
child: RaisedButton(
color: Colors.pink,
child: Text(
'Go to Screen 2',
style: TextStyle(
color: Colors.white,
),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return Screen2();
},
),
);
},
),
),
),
);
}
}
//screen_2.dart
import 'package:flutter/material.dart';
class Screen2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue,
title: Text('Screen 2'),
),
body: Center(
child: RaisedButton(
color: Colors.blue,
child: Text('Go Back To Screen 1'),
onPressed: () {},
),
),
);
}
}
onPressed of Screen1 class should show Screen2 but it's not happening.
I tried this and it does move to Screen2:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Screen1(),
);
}
}
//screen_1.dart
class Screen1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Screen 1'),
),
body: Container(
child: Center(
child: RaisedButton(
color: Colors.pink,
child: Text(
'Go to Screen 2',
style: TextStyle(
color: Colors.white,
),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return Screen2();
},
),
);
},
),
),
),
);
}
}
//screen_2.dart
class Screen2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue,
title: Text('Screen 2'),
),
body: Center(
child: RaisedButton(
color: Colors.blue,
child: Text('Go Back To Screen 1'),
onPressed: () {},
),
),
);
}
}
This may be because StatelessWidget is part of material.dart yet you failed to import it in the first dart file.

Flutter navigation by route name in statefull widget

i am trying to go on another page using navigation, but i am getting error;
Navigator operation requested with a context that does not include a
Navigator.
i am just trying to move on next page, i followed flutter documentations for this stateless widget but how to do with state full widget.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State createState() => new MyApp1();
}
class MyApp1 extends State<MyApp> {
List<Widget> _listSection = [];
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Share IDEASS',
initialRoute: '/',
routes: {
'/second': (context) => SecondScreen(),
},
home: Scaffold(
appBar: AppBar(
title: Text('IDEAS'),
),
body: Container(
child: Stack(
children: [
floatingButton(),
],
),
),
),
);
}
Widget floatingButton() {
return Container(
padding: const EdgeInsets.all(30),
alignment: Alignment.bottomRight,
child: FloatingActionButton(
onPressed: () {
Navigator.pushNamed(context, "/SecondScreen");
},
child: Text("+"),
backgroundColor: Colors.blue,
),
);
}
}
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}
You should use the named route you created.
Widget floatingButton(BuildContext context) { // added context as a parameter
return Container(
padding: const EdgeInsets.all(30),
alignment: Alignment.bottomRight,
child: FloatingActionButton(
onPressed: () {
Navigator.pushNamed(context, "/second"); // Changed this to use the named route
},
child: Text("+"),
backgroundColor: Colors.blue,
),
);
}
}
then use the following
body: Container(
child: Stack(
children: [
floatingButton(context),
],
),
),
The situation here is that the floatingButton() uses a context with the navigator to push the given page route. But the context used is provided in the parent Widget(MaterialApp) it self, which doesn't include a Navigator, hence the error.
So, Try this approach:
Separate the Home widget from the MaterialApp, like below:
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Share IDEASS',
initialRoute: '/',
routes: {
'/second': (context) => SecondScreen(),
},
home: HomePage(),
);
Create a stateless widget containing the Scaffold:
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('IDEAS'),
),
body: Container(
child: Stack(
children: [
floatingButton(),
],
),
),
);
}
}
Hope it helps. Let me know if this doesn't work.
You have made two mistakes because of which your code is not working:
You have used wrong route name. Replace /SecondScreen with /second
You have used wrong context. You can get Navigator only if your widget has MaterialApp as it's parent and here you are using context of MyApp1 so it is not working.
Following is a working code for your reference.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State createState() => new MyApp1();
}
class MyApp1 extends State<MyApp> {
List<Widget> _listSection = [];
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Share IDEASS',
initialRoute: '/',
routes: {
'/second': (context) => SecondScreen(),
},
home: AppContent(),
);
}
}
class AppContent extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('IDEAS'),
),
body: Container(
child: Stack(
children: [
floatingButton(context),
],
),
),
);
}
Widget floatingButton(BuildContext context) {
return Container(
padding: const EdgeInsets.all(30),
alignment: Alignment.bottomRight,
child: FloatingActionButton(
onPressed: () {
Navigator.pushNamed(context, "/second");
},
child: Text("+"),
backgroundColor: Colors.blue,
),
);
}
}
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}