I am currently developing a flutter app. I have tested a feature on Android and there everything worked, when I test it on IOS, unfortunately the following error is called:
_CastError (type 'Contract' is not a subtype of type 'Damage' in type cast)
The code to which the error refers is the following:
final Damage damage = item as Damage;
return Scaffold(
floatingActionButton: FloatingActionButton(
tooltip: 'Add',
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) => AddDocumentsPage(
damage: damage,
),
),
);
},
child: Icon(Icons.add),
),
body: DocumentsList(
attribute: 'date',
documentable: item,
),
);
You should be very cautious when using the as keyword. It is very likely that your item isn't of type Damage and therefore cannot be cast into one.
Your best option here would be to create a new Damage object and fulfilling it with the data you need from item.
Related
I'm trying to add the CupertinoNavigationBar with endDrawer, I try to add Gesture Detector on trailing, but isn't work, shows this:
The following assertion was thrown while handling a gesture:
flutter: `Scaffold.of()` called with a context that does not contain a Scaffold.
flutter: No Scaffold ancestor could be found starting from the context that was passed to `Scaffold.of()`. This
flutter: usually happens when the context provided is from the same StatefulWidget as that whose build
I already tried to add the key to scaffold and try opened with the key, I try too with scaffold context in appbar
AppBar:
Scaffold(
appBar: CupertinoNavigationBar(
transitionBetweenRoutes: true,
trailing: IconButton(
icon: Icon(Icons.menu),
onPressed: () {
Scaffold.of(context).openEndDrawer();
},),
actionsForegroundColor: Colors.white,
middle: Text('Lejour', style: TextStyle(color: Colors.white)),
backgroundColor: Theme.of(context).primaryColor),
endDrawer: DrawerMenu() // my own class,
body: // ...body
I expect my trailing icon from CupertinoNavigationBar open the endDrawer with
Scaffold.of(context).openEndDrawer();
This is a common issue when you try to use Scaffold.of(context) . You should read the error log.
No Scaffold ancestor could be found starting from the context that was
passed to Scaffold.of()
To solve your issue, use the Builder widget to generate a new a context.
trailing: Builder(
builder: (context) {
return IconButton(
icon: Icon(Icons.menu),
onPressed: () {
Scaffold.of(context).openEndDrawer();
},
);
},
),
The context:
I stumbled upon a minor crash while testing a ListView of Dismissibles in Flutter. When swiping a dismissible, a Dialog is shown using the confirmDismiss option, for confirmation. This all works well, however the UI crashes when testing an unlikely use case. On the page are several options to navigate to other (named) routes. When a dismissible is swiped, and during the animation an option to navigate to a new route is tapped, the crash happens.
How to replicate the crash:
Dismiss the Dismissible
During the animation that follows (the translation of the position of the dismissible), tap on an action that brings you to a
new route. The timeframe to do this is minimal, I've extended it in the example.
The new route loads and the UI freezes
For reference, this is the error message:
AnimationController.reverse() called after AnimationController.dispose()
The culprit is the animation that tries to reverse when it was already disposed:
package:flutter/…/widgets/dismissible.dart:449
Things I've tried:
Initially, I tried checking this.mounted inside the showDialog builder but quickly realised the problem is not situated there.
Another idea was to circumvent the problem by using CancelableOperation.fromFuture and then cancelling it in the dispose() method of the encompassing widget, but that was to no avail.
What can I do solve or at least circumvent this issue?
The code (can also be found and cloned here):
// (...)
class _DimissibleListState extends State<DimissibleList> {
int childSize = 3;
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: childSize,
itemBuilder: (context, index) {
if (index == 0) {
return _buildNextPageAction(context);
}
return _buildDismissible();
},
),
);
}
Widget _buildNextPageAction(context) {
return FlatButton(
child: Text("Go to a new page"),
onPressed: () => Navigator.of(context).pushNamed('/other'),
);
}
Dismissible _buildDismissible() {
GlobalKey key = GlobalKey();
return Dismissible(
key: key,
child: ListTile(
title: Container(
padding: const EdgeInsets.all(8.0),
color: Colors.red,
child: Text("A dismissible. Nice."),
),
),
confirmDismiss: (direction) async {
await Future.delayed(const Duration(milliseconds: 100), () {});
return showDialog(
context: context,
builder: (context) {
return Dialog(
child: FlatButton(
onPressed: () => Navigator.of(context).pop(true),
child: Text("Confirm dismiss?"),
),
);
},
);
},
resizeDuration: null,
onDismissed: (direction) => setState(() => childSize--),
);
}
}
I had almost same problem with confirmDismiss ,in my case I was using (await Navigator.push() ) inside of confirmDismiss to navigate to another screen but in return I faced this error :
AnimationController.reverse() called after
AnimationController.dispose()
so to solve my problem inside of confirmDismiss I call a future function out side of confirmDismiss (without await ) and then add return true or false after that function call to finish animation of confirmDismiss.
Working on a flutter/dart project I'm currently almost always thinking about a way to decrease my code size, considering that one of the things would be using arrow functions to avoid the brackets.
However I can't find a way to keep them in a nice look, e.g. if I use this code:
#widget
Widget poscompExams() => StoreConnector<AppState, ViewModel>(
converter: ViewModel.fromStore,
builder: (BuildContext context, ViewModel vm) => Scaffold(
body: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: vm.poscomp.exams.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text('Test'),
subtitle: const Text('Inserção das provas em andamento'),
leading: const Icon(Icons.computer),
onTap: () => {}
);
},
),
),
],
);
},
);
It would be much nicer if the look was like this:
#widget
Widget poscompExams() =>
StoreConnector<AppState, ViewModel>(
converter: ViewModel.fromStore,
builder: (BuildContext context, ViewModel vm) =>
Scaffold(
body: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: vm.poscomp.exams.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text('Test'),
subtitle: const Text('Inserção das provas em andamento'),
leading: const Icon(Icons.computer),
onTap: () => {}
);
},
),
),
],
);
},
);
I research about some way and find the dart_style, but it seems to follow the general same pattern to format.
It would be nice something like prettier on Javascript, with flag options.
Generally, if you get past six or seven levels of indentation, it's time to refactor. This will make it easier for you to override parts of it for variations, and easier for people reading and maintaining your code to understand your intent.
In your specific code, I'd take the ListView.builder out as a separate method in your class. There are IDE operations to help with that kind of refactor.
Also, in your code, () => {} is a function returning an empty map. You should fix that to just () {}.
I have problem with showDialog, when i press nothing happens but if i use Navigator.pushNamed(context, "/screen1") it works. I can not run Navigator.pop(context), it does not return any errors.
_showDialog(BuildContext context) {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text("Alert Dialog title"),
actions: <Widget>[
new FlatButton(
child: new Text("Back"),
onPressed: () {
//Navigator.pushNamed(context, "/screen1");
Navigator.pop(context);
},
),
],
);
});}
In my build() :
IconButton(
iconSize: 30.0,
onPressed: () => _showDialog(context),
icon: Icon(
Icons.clear,
color: Colors.white,
),
)
had the same issue .having useRootNavigator: false, in showDialog params solved my issue .
Use pop() two times:-
Navigator.of(context).pop();
Navigator.of(context).pop();
Reason: first pop function dismiss the dialog and Second pop function close the screen
The above answer should be accepted for this question, just elaborating the above answer
return showDialog(
context: context,
useRootNavigator: false, //this property needs to be added
builder: (BuildContext context) {....});
Try calling Navigator.of(context).pop(); instead of Navigator.pop(context);
For closing dialogs, you can also use:
Navigator.pop(context, true);
Source: https://docs.flutter.io/flutter/widgets/Navigator/pop.html
For those who have nested/multiple Navigators, you can also use the pop method as shown below (notice the named parameter rootNavigator set to true):
Navigator.of(context, rootNavigator: true).pop();
As suggested by others, I tried setting the useRootNavigator in the showDialog as false but this way the barrierColor wasn't covering the whole screen (it was only covering the screen displayed by Navigator object the dialog was in).
In summary, you can use the way showed above if you have nested navigators and want to achieve having the barrierColor covering the whole screen.
The code below is a simplified version of the original, where my goal is to have a list of list tiles: List where I can keep track of newly created ListTile Widgets and which I can use as an argument to pass to a ListView.
class Notes extends StatefulWidget{
_NotesState createState() => new _NotesState();
}
class _NotesState extends State<Notes>{
List<ListTile> notes =[];
void addNewNote(){
setState((){
notes.add(new ListTile(title: new Text("Broccolli")));
}
#override
Widget build(BuildContext context){
return new Scaffold(
appBar: new AppBar(title: "NOTES"),
body: new Stack(
children: <Widget>[
// The notes
new Container(
child: new ListView(
children: new List.from(notes, growable: false),
)
),
// The add notes button
new FloatingActionButton(
tooltip: 'Add a note',
onPressed: addNewNote,
)
],
),
);
}
This used to work just fine before the last update to flutter where Dart 2 was introduced, but now I receive the following message:
type 'List<dynamic>' is not a subtype of type 'List<Widget>' where
List is from dart:core
List is from dart:core
Widget is from package:flutter/src/widgets/framework.dart
The issue stems from: new List.from(notes, growable: false)
My reason for doing this is because when I just pass the list as an argument to ListView.children flutter does not register a change and the new elements of the list are not displayed, so I just create a new List and my issue was resolved. However this is no longer viable
You have to specify the type of your List created by new List.from or else it defaults to dynamic.
The fact is that with strong-mode, List<dynamic> is not assignable to List<whatever> anymore. So you must make sure your List has the correct type.
In your case a simple new List<Widget>.from(notes) will do the trick