Routemaster replace is doing push - flutter

import 'package:flutter/material.dart';
import 'package:routemaster/routemaster.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({Key? key}) : super(key: key);
late final RoutemasterDelegate _routerDelegate = RoutemasterDelegate(
routesBuilder: (context) => RouteMap(
routes: buildRoutingTable(
routerDelegate: _routerDelegate,
),
),
);
#override
Widget build(BuildContext context) => MaterialApp.router(
title: 'Flutter Demo',
theme: ThemeData(
useMaterial3: true,
colorSchemeSeed: Colors.lightGreenAccent,
),
routeInformationParser: const RoutemasterParser(),
routerDelegate: _routerDelegate,
);
}
Map<String, PageBuilder> buildRoutingTable({
required RoutemasterDelegate routerDelegate,
}) =>
{
PathConstants.tabContainerPath: () => MaterialPage(
name: 'first-screen',
child: FirstScreen(
onNavigate: () => routerDelegate.replace(
_PathConstants.secondScreen,
),
),
),
PathConstants.secondScreen: () => const MaterialPage(
name: 'second-screen',
child: SecodScreen(),
),
};
class _PathConstants {
const PathConstants.();
static String get tabContainerPath => '/';
static String get secondScreen => '${tabContainerPath}second-screen';
}
class FirstScreen extends StatelessWidget {
final VoidCallback onNavigate;
const FirstScreen({
Key? key,
required this.onNavigate,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Fisrt screen'),
),
body: Center(
child: ElevatedButton(
onPressed: onNavigate,
child: const Text('Replace'),
),
),
);
}
}
class SecodScreen extends StatelessWidget {
const SecodScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Second screen'),
),
);
}
}

Related

Scaffoldmessenger widget ancestor problem

void main() async {
WidgetsFlutterBinding.ensureInitialized();
await SharedPrefs.init();
runApp(MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => UserProvider()),
Provider(
create: (context) => AuthService(),
),
],
child: Builder(builder: (context) {
return const MyApp();
})));
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
context.read<AuthService>().getUserData(context);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Amazon Clone',
onGenerateRoute: (settings) => generateRoute(settings),
theme: ThemeData(
scaffoldBackgroundColor: GlobalVariables.backgroundColor,
colorScheme:
const ColorScheme.light(primary: GlobalVariables.secondaryColor),
appBarTheme: const AppBarTheme(
elevation: 0,
iconTheme: IconThemeData(color: Colors.black),
),
),
home: Builder(builder: (context) {
return context.watch<UserProvider>().user.token.isNotEmpty
? const HomeScreen()
: const AuthScreen();
}));
}
}
i am using snackbar from utils file i get no scaffoldmessenger widget found error.I tried to use builder scaffoldmessengerkey but didnt work.what can i do.i used try catch with snackbar.What is the solve of my problem
You need both MaterialApp and a Scaffold widget in the tree before using ScaffoldMessenger. For example:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp( // required MaterialApp
title: _title,
home: Scaffold( // required Scaffold
appBar: AppBar(title: const Text(_title)),
body: const Center(
child: MyStatelessWidget(),
),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return OutlinedButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('A SnackBar has been shown.'),
),
);
},
child: const Text('Show SnackBar'),
);
}
}

Unable to run my Flutter app with Firebase and having an error

The error is following:
../../flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_platform_interface-4.5.0/lib/src/pigeon/messages.pigeon.dart(199,7): error GE33FC089: 'flutthrow' isn't a type. [C:\Users\Muhammad Umar\Documents\flutter_projects\android_ios\build\windows\flutter\flutter_assemble.vcxproj]
and Here is my main.dart file, can anyone tell me what's wrong here?
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final Future<FirebaseApp> _fbApp = Firebase.initializeApp();
MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: FutureBuilder(
future: _fbApp,
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Text('Something went wrong');
} else if (snapshot.hasData) {
return const MyHomePage(title: 'My Amazing Counter App!');
}
return const Center(
child: CircularProgressIndicator(),
);
}),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}

Dar/Flutter constructor structure

The following code is from an example from "dartpad.dev" web site. Within the class MyHomePage extends StatefulWidget { ..., in constructor part, I can't understand what's going on. I've been studying dart for a reasonable time, but still it's hard for me to figure out what's happenning. required this.title is OK, however why there are Key? key and : super(key: key) ?
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({
Key? key,
required this.title,
}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}

Flutter: MaterialApp throws Null check operator used error

Here is where I instantiate my MaterialApp:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'My New App';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
initialRoute: '/special',
routes: {
'/special': (context) => const SpecialPage(),
'/another': (context) => const AnotherPage()
});
}
}
The pages are very similar. Here is the Special page:
class SpecialPage extends StatelessWidget {
const SpecialPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Special Stuff'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/another');
},
child: const Text('Special Content Goes Here'),
),
),
);
}
When I try to compile I get the error: Null check operator used on a null value. Why?
The error message indicates the problem occurs in the construction of MaterialApp.
Remove the const in the build method of MyApp
Like so:
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
initialRoute: '/special',
routes: {
'/special': (context) => const SpecialPage(),
'/another': (context) => const AnotherPage()
});
}

How to scroll underlying widget in Flutter?

I have a simple app with two screens. The first screen is a scrollable ListView and the second screen is basically empty and transparent. If I pushed the second screen with Navigator.push() on top of the first screen I'd like to be able to scroll the underlying first screen.
Here is my code:
import 'package:flutter/material.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: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
itemBuilder: (context, index) {
return Text("$index");
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
PageRouteBuilder<void>(
opaque: false, // push route with transparency
pageBuilder: (context, animation, secondaryAnimation) => Foo(),
),
);
},
child: Icon(Icons.add),
),
);
}
}
class Foo extends StatelessWidget {
const Foo({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white.withOpacity(0.5),
appBar: AppBar(
title: Text("I'm on top"),
),
);
}
}
How can scroll the list in the backgound while the second screen is in the foreground?
Although this is not a solution with a second screen, it creates a similar effect using the Stack and IgnorePointer widgets:
import 'package:flutter/material.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: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _applyOverlay = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: _applyOverlay
? IconButton(
icon: Icon(
Icons.arrow_back_ios_sharp,
),
onPressed: () => setState(
() => _applyOverlay = false,
),
)
: null,
title: Text(_applyOverlay ? 'Overlay active' : widget.title),
),
body: Stack(
children: [
ListView.builder(
itemBuilder: (context, index) {
return Text("$index");
},
),
if (_applyOverlay)
// Wrap container (or your custom widget) with IgnorePointer to ignore any user input
IgnorePointer(
child: Container(
height: double.infinity,
width: double.infinity,
color: Colors.white.withOpacity(0.5),
),
),
],
),
floatingActionButton: _applyOverlay
? null
: FloatingActionButton(
onPressed: () {
setState(() => _applyOverlay = true);
},
child: Icon(Icons.add),
),
);
}
}
I found a solution that works even with two screens. The idea is to have two ScrollControllers each in one screen and add a listener the ScrollController in the overlay that triggers the ScrollController of the underlying widget.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
const INITIAL_OFFSET = 5000.0;
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ScrollController controller = ScrollController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
controller: controller,
itemBuilder: (context, index) {
return Text("$index");
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
PageRouteBuilder<void>(
opaque: false, // push route with transparency
pageBuilder: (context, animation, secondaryAnimation) => Foo(
controller: controller,
),
),
);
},
child: Icon(Icons.add),
),
);
}
}
class Foo extends StatefulWidget {
final ScrollController controller;
const Foo({required this.controller, Key? key}) : super(key: key);
#override
State<Foo> createState() => _FooState();
}
class _FooState extends State<Foo> {
final ScrollController controller = ScrollController(
initialScrollOffset: INITIAL_OFFSET,
);
#override
void initState(){
super.initState();
controller.addListener(() {
widget.controller.animateTo(
controller.offset - INITIAL_OFFSET,
duration: const Duration(milliseconds: 1),
curve: Curves.linear,
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white.withOpacity(0.5),
appBar: AppBar(
title: Text("I'm on top"),
),
body: SingleChildScrollView(
controller: controller,
child: Container(
height: 2 * INITIAL_OFFSET,
color: Colors.white.withOpacity(0.5),
),
),
);
}
}
There are still a few problems with this workaround:
This does not work for infinite lists.
The scroll behavior is bad because the background is only scrolled when the scroller ends his gesture by put the finger up.
The sizes of the both screens doesn't match. That leads to bad effects like scrolling in areas that doesn't exists in the other screen.
I finally found a satisfying answer that does not contain any kind of dirty workarounds. I use a Listener in the second screen to detect OnPointerMoveEvents which are basically scroll events.
import 'package:flutter/material.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: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ScrollController controller = ScrollController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView.builder(
controller: controller,
itemBuilder: (context, index) {
return Text("$index");
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
PageRouteBuilder<void>(
opaque: false, // push route with transparency
pageBuilder: (context, animation, secondaryAnimation) => Foo(
controller: controller,
),
),
);
},
child: Icon(Icons.add),
),
);
}
}
class Foo extends StatefulWidget {
final ScrollController controller;
const Foo({required this.controller, Key? key}) : super(key: key);
#override
State<Foo> createState() => _FooState();
}
class _FooState extends State<Foo> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white.withOpacity(0.5),
appBar: AppBar(
title: Text("I'm on top"),
),
body: Listener(
onPointerMove: (event){
var newPosition = widget.controller.position.pixels - event.delta.dy;
widget.controller.jumpTo(newPosition);
},
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
color: Colors.red.withOpacity(0.5),
),
),
);
}
}