i send an idd from another screen when i want to navigate to this WaitingScreen
Now when i want to use the idd , I get an error in the line
FirebaseFirestore.instance.collection('ambulance').doc(idd).get()
class WaitingScreen extends StatefulWidget {
final String idd;
String? Key;
WaitingScreen({required this.idd}) : super();
_WaitingScreenState createState () => _WaitingScreenState( ) ;
}
class _WaitingScreenState extends State<WaitingScreen> with SingleTickerProviderStateMixin{
late AnimationController _controller;
#override
void initState() {
super.initState();
_controller =
AnimationController(vsync: this, duration: Duration(minutes: 5));
_controller.forward();
}
#override
Widget build(BuildContext context) {
String? valuee;
return FutureBuilder<DocumentSnapshot>(
future: FirebaseFirestore.instance.collection('ambulance').doc(idd).get(),
When using a stateful widget, you need to reference variables on the widget itself by using the following construction:
widget.idd
By using the prefix widget., you make sure to access the variables on the widget, and not on the state you are in.
Related
I want to assign the value of currentUser.profilepictureURL to ListImage.
But if I put the initState outside of the widget build, it will be out of scope. Please tell me.
class _MyHomePageState extends ConsumerState<MyHomePage> {
var listImage = [];
#override
Widget build(BuildContext context) {
final currentUser = ref.watch(userModelProvider);
void initState() {
listImage.add(currentUser.profilePictureURL);
super.initState();
}
return Container();
}
}
The way your are using initState is wrong. InitState is an #override and it should not to be used inside a build method.
try this:
class _MyHomePageState extends ConsumerState<MyHomePage> {
var listImage = [];
#override
Widget build(BuildContext context) {
final currentUser = ref.watch(userModelProvider);
listImage.add(currentUser.profilePictureURL);
return Container();
}
}
I want a default empty controller for my custom text field but its not allowing with both ways
You cannot have a const constructor and use a non constant default value.
Therefore you would have to remove the const keyword before CustomTextField. But you can also not have a non-constant value as an optional parameter.
So a suggestion is to change the stateless widget to a stateful widget and initialize the controller in the init() method if no controller is provided with the the contructor.
It's better to set a default controller like this, so we can dispose it to prevent memory leaks:
import 'package:flutter/material.dart';
class CustomTextField extends StatefulWidget {
const CustomTextField({
Key? key,
this.controller,
}) : super(key: key);
final TextEditingController? controller;
#override
State<CustomTextField> createState() => _CustomTextFieldState();
}
class _CustomTextFieldState extends State<CustomTextField> {
late TextEditingController _controller;
#override
void initState() {
super.initState();
_controller = widget.controller ?? TextEditingController();
}
#override
void dispose() {
if (widget.controller == null) {
// if we made the controller ourselves, we dispose it ourselves
// but if it's made outside of this widget, it should be disposed outside
_controller.dispose();
}
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container();
}
}
I have home screen which two tabs. now when I get to home tab and got to search instantly. I get red screen for slight second and then all widgets get loaded.
Now where problem is,
in initState() I'm assigning store.filteredPOI to widget.floorPlan.pois.
I'm getting store.filteredPOI from a network call which will take some time. so in that fraction of time widget.floorPlan is null so how can I show a loader to prevent the red error screen,
code
class SearchTab extends StatefulWidget {
final FloorPlan floorPlan;
final bool isIndoorMapVisible;
final NetworkStatus networkStatus;
SearchTab({this.floorPlan, this.isIndoorMapVisible,this.networkStatus});
#override
_SearchTabState createState() => _SearchTabState();
}
class _SearchTabState extends State<SearchTab> {
final TextEditingController textController = TextEditingController();
SearchStore store;
#override
void initState() {
store = SearchStore();
store.filteredPOI = widget.floorPlan.pois; //<<<<<<<<
super.initState();
}
#override
Widget build(BuildContext context) {
return (...)
what I ended up doing was add the operation inside built method
#override
Widget build(BuildContext context) {
store.filteredPOI = widget.floorPlan.pois;
return (...)
I made a custom transition for my iOS project, and now I want to move the project to Flutter. The transition is fading out the old page, and fading in the new one.
But I cannot achieve this by overriding the PageRoute.
I did some research on this:
There's a similar question
Animate route that is going out / being replaced
From the accepted answer, I know there's a parameter 'secondaryAnimation' which may be useful to achieve it, but after trying to use the code from it, I still cannot animate the old page, all transitions have happened to the new page (the 'child' widget).
Can I get an 'old page' instance from the buildTransition method for animating? Or is there a better way to animate the old page?
Thanks!
I think that secondaryAnimation is used when transitioning to another page. So for your initial route, you'd have to specify the animation of it going away using secondaryAnimation and on your second page you use animation to animate how it appears.
It's a bit awkward that you have to use secondaryAnimation when creating the first route, because it means that it will be used for any transition away from that route. So, with PageRouteBuilder, you can't, for example, let the old page slide to the left when transitioning to page B but slide up when transitioning to page C.
I wrote two classes to achieve animating the old page.
PageSwitcherBuilder is a widget builder to animate old page.
PageSwitcherRoute is a route class to navigate new page.
Examples on DartPad
Here is my script.
class PageSwitcherBuilder extends StatefulWidget {
const PageSwitcherBuilder(
{Key? key,
required this.builder,
this.duration = const Duration(milliseconds: 500),
this.reverseDuration = const Duration(milliseconds: 500)})
: super(key: key);
final Duration duration;
final Duration reverseDuration;
final Widget Function(AnimationController controller) builder;
#override
State<PageSwitcherBuilder> createState() => _PageSwitcherBuilderState();
}
class _PageSwitcherBuilderState extends State<PageSwitcherBuilder>
with TickerProviderStateMixin {
late final AnimationController _controller = AnimationController(
vsync: this,
duration: widget.duration,
reverseDuration: widget.reverseDuration,
);
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return widget.builder(_controller);
}
}
class PageSwitcherRoute extends PageRouteBuilder {
PageSwitcherRoute({
required this.controller,
required Widget page,
}) : super(pageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return page;
}) {
willDisposeAnimationController = false;
}
#override
final AnimationController controller;
#override
AnimationController createAnimationController() {
return controller;
}
}
You may also check this ZoomPageTransitionsBuilder class to change default transitions.
Workaround that I've come up with is to observe pushes and pops of routes and animte during these.
Create a Route Wrapper using RouteObserver
Run animation on didPushNext
Reverse animation on didPopNext
Wrap all screens that you want to animate on exit and on reenter.
import 'package:flutter/material.dart';
class ScreenSlideTransition extends StatefulWidget {
const ScreenSlideTransition({super.key, required this.child});
final Widget child;
#override
State<ScreenSlideTransition> createState() => _ScreenSlideTransitionState();
}
class _ScreenSlideTransitionState extends State<ScreenSlideTransition>
with RouteAware, TickerProviderStateMixin {
late final AnimationController _controller;
#override
Widget build(BuildContext context) {
final screenWidth = -MediaQuery.of(context).size.width;
return AnimatedBuilder( // Whatever animation you need goes here
animation: _controller,
builder: (BuildContext context, Widget? child) => Transform.translate(
offset: Offset(screenWidth * _controller.value, 0),
child: widget.child));
}
#override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 1000));
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
routeObserver.subscribe(this, ModalRoute.of(context)!);
}
#override
void dispose() {
_controller.dispose();
routeObserver.unsubscribe(this);
super.dispose();
}
#override
void didPopNext() {
_controller.reverse();
super.didPopNext();
}
#override
void didPushNext() {
_controller.forward();
super.didPushNext();
}
}
In order to make the above code work make sure to initialise RouteObserver (see docs)
final RouteObserver<ModalRoute<void>> routeObserver = RouteObserver<ModalRoute<void>>();
void main() {
runApp(MaterialApp(
home: Container(),
navigatorObservers: <RouteObserver<ModalRoute<void>>>[ routeObserver ],
));
}
Remember to set the same Duration for AnimationController in ScreenSlideTransition and duration for transitionsBuilder if you want to synchronise in/out animation.
How to hot-reload fields of a State subclass in Flutter?
I know that the modifying the initial value of fields isn't taken into account during hot-reload and that I can use hot-restart for them. But this is painfully slow.
Is there any way to ease the process?
A typical use-case would be animations, especially AnimationController. As it is stored inside a State field, but we usually want to iterate over its duration. Example:
class MyAnim extends StatefulWidget {
#override
_MyAnimState createState() => _MyAnimState();
}
class _MyAnimState extends State<MyAnim> with SingleTickerProviderStateMixin {
AnimationController animationController;
#override
void initState() {
animationController =
AnimationController(vsync: this, duration: const Duration(seconds: 1));
super.initState();
}
#override
void dispose() {
animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container();
}
}
State provides a custom lifecycle hook for hot-reloads: reassemble
You can freely override that method to have custom hot-reload behaviors. Don't worry, this method will never be called in production.
With a small tweak you'd get the following:
class _MyAnimState extends State<MyAnim> with SingleTickerProviderStateMixin {
AnimationController animationController;
#override
void initState() {
animationController = AnimationController(vsync: this);
_initializeFields();
super.initState();
}
void _initializeFields() {
animationController.duration = const Duration(seconds: 1);
}
#override
void reassemble() {
_initializeFields();
super.reassemble();
}
#override
void dispose() {
animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container();
}
}
Now, whenever you modify your State class, it will correctly update AnimationController's duration.