How to tap all items of a list or a grid in a Flutter widget test? - flutter

In my Flutter widget tests I want to tap all (or first n) items in a list or grid view.
I already came up with a solution and although it seems to work, it looks overly complicated to find the tap target again by key:
for (final element in find.byType(ListTile).evaluate()) {
await tester.tap(find.byKey(element.widget.key!));
}
Is there a more elegant way to do it?

You can tap at a certain location on the widget:
e.g. tapping at center of the widget
for (final element in find.byType(ListTile).evaluate()) {
await tester.tapAt(tester.getCenter(find.byWidget(element.widget)));
}

Related

I want to make my Icons Automatically go to next Row in flutter if previous row gets completrly filled with icons

I am building a quiz app using Dart flutter in that some questions will get displayed and users have to click on true or false buttons depending upon question is right or wrong. To tell users that they are right or wrong icon (✓ or ✘) will get displayed in bottom row every time they choose answer by clicking on either of the button. But in flutter if row gets completely filled i got error
value: Not in inclusive range. So i want that icon should automatically go to next row.
Heres the short code which i tried:
List scorekeeper = [];
void score(bool userpickedanswer) {
setState((){
if (userpickedanswer == correctanswer) {
scorekeeper.add(Icon(Icons.check, color: Colors.green,));
}
else {
scorekeeper.add(Icon(Icons.close, color: Colors.red,));
}
}
Row {
childeren : scorekeeper
You can use the Wrap widget instead of the Row widget and when the line of icon fills to the end the Wrap widget makes another line automatically
Use the code like this:
Wrap(
children: scorekeeper,
),
You can use a wrap instead of a row. It prevents overflow by displaying the items depending on the available space:
https://api.flutter.dev/flutter/widgets/Wrap-class.html

Custom Event listeners in flutter

I have a widget with a list and a button with a tree dot icon in every row that shows and hides a panel in its own row. I only want one panel open in the list. When I click on a row button, I'd like to close the panels of the other rows list.  All the buttons in the list are siblings. I'd like to send an event to the other rows' code to close the panels. Which is the correct manner of flutter?  
I have tried NotificationListener but it does not work because the components to be notified are not their parents.
The question is if the correct thing to do is to use the event_listener library or to use streams. I'm new to flutter/dart and streams seem too complex to me. It's a very simple use case and in this entry
Flutter: Stream<Null> is allowed?
they say
*
Some peoples use streams as a flux of events instead of a value
changing over time, but the class isn't designed with this in mind.
They typically try to represent the following method as a stream:
So with simple events with 0 or 1 argument. event_listener or Streams?
This is the screen I'm working on. I want that when one yellow button panel opens the other one closes.
Your question is broad and it seems to be a design question, i.e. it doesn't have a right answer.
However, I don't think you should use Streams or EventListeners at all in this case, because you should not make components in the same layer communicate with each other. Components should only communicate with their parents and children, otherwise your code will increase in complexity really fast. That's even documented in flutter_bloc.
Other than that, if you don't lift state up, i.e. move the responsibility of triggering the removal of the other rows to a parent Widget, than you're fighting against Flutter instead of letting it help you.
It's easy to create a parent Widget, just wrap one Widget around it. What you want to do is hard, so why would try to communicate with sibling widgets instead of using what's Flutter designed to do?
This is a suggestion:
class _NewsSectionState extends State<NewsSection> {
Widget build(BuildContext context) {
return ListView.builder(
itemCount: newsInSection.length;
itemBuilder: (_, int index) => NewsTile(
title: Text('${newsInSection[index].title}')
onDismiss: () => onDismiss(index),
// I don't know how you set this up,
// but () => onDismiss(Index)
// should animate the dismiss of the Row with said index
),
);
}
}
class NewsRow extends StatefulWidget {
final void Function() onDismiss;
#override
State<NewsRow> _createState => _NewsRowState();
}
class _NewsRowState extends State<NewsRow> {
Widget build(BuildContext context) {
return Row(
children: [
// title
// home button
// fav button
// remove button
IconButton(
Icons.close,
onPressed: widget.onDismiss,
),
],
);
}
}

How to execute function on Navigator pop from a nested stateless widget

I have an UI like the image. The listView is generate from data coming from FutureBuilder -> future.
Each item in the list is a ListTile and the red marked part is another stateless widget that navigates to another page do do some update operation.
I am going from one screen to another using Navigator.of(context).pushNamed(screenName).
If I want to do some operation when then Navigator.of(context).pop() then I can use
Navigator.of(context).pushNamed(AddFamilyMember.routeName).then((value) => {})
But I can not perform it from a list item in the list
So how to do it?
The code would be too complicated that is why I am drawing this image
So according to the image when I come back from screen 4 to screen 2 I can call Navigator.of(context).pushNamed(AddFamilyMember.routeName).then((value) => {})
I want to do the same when I come back from screen 6 to screen 2
Please note image 3 is not a screen . this widget represent one list item from the list view
Marked 7 is the widget that takes to screen 6
So how to do it?
what you can do here when you naviagte to other screen make your navigation as async and save the vale in variable the based on this variable you can perform a funtion .....
onTap: () async {
var result = await Navigator.of(context).pushNamed(
Routes.inviteFamilyMember,
arguments: {'data': null});
if (result == "Update") {
_refreshIndicatorKey.currentState.show();
}
}
on poping back retun value true or false based on this value trigger the refresh indicator still have doubts let me know

Detect user created widgets in flutter widget tree

I've been working on a problem today to detect certain widgets in the widget tree so I've been playing around with context.visitChildElements and element. visitChildren. I can see all the widgets in the tree, but there's just too many.
I looked at the way the flutter widget inspector does it and they have some internal expectations that won't exist within other users code bases. The example, I have a scaffold with a body Center and a child Material button. Passing the context to my function below prints out about 200+ widgets with those three scattered in between. I would like to only print out those three, or at least elliminate all widgets created by Flutter automatically and not created by the code the user supplied.
List<WidgetInfo> getElements(BuildContext context) {
var widgetsOfInterest = <WidgetInfo>[];
widgetsOfInterest.clear();
int indentation = 0;
void visitor(Element element) {
indentation++;
Key? key = element.widget.key;
String className = element.widget.runtimeType.toString();
while (element.findRenderObject() is! RenderBox) {}
RenderBox box = element.findRenderObject() as RenderBox;
var offset = box.getTransformTo(null).getTranslation();
final indent = ' ' * indentation;
// Here I want to check if this is a widget we created and print its name and offset
if (debugIsLocalCreationLocation(element)) print('$className $offset');
if ((MaterialButton).toString() == className) {
widgetsOfInterest.add(WidgetInfo(
indentation: indentation,
size: box.size,
paintBounds: box.paintBounds.shift(
Offset(offset.x, offset.y),
),
key: key,
className: className,
));
}
element.visitChildren(visitor);
}
context.visitChildElements(visitor);
return widgetsOfInterest;
}
If anyone have any insights or experience with the Flutter widget tree that could point me in the right direction I would appreciate that.
it's obviously seems not the best solution here(and will increase unnecessary code) but this might work.
you can create a custom widget key that have some prefix inside of it and use it in every component you want it to be detected
for example
//1
Appbar(key: FSKey())
//2
Center(key:FSKey("awesome_widget"))
internally if you have access to those key while you iterate through elements you can detect those widgets using the prefix you set.
actuall key values
//1
"fskey_1273zj72ek628"
//2
"fskey_awesome_widget"
again this might not be a very optimal solution but iit gives you some control of what parts of the tree you want it to be detected and eventually if there is no other way.. this will work.

How to dismiss flutter dismissable widget programmatically?

Is it possible to dismiss dismissable programmatically? Not by swipe, but by let's say button click.
The only thing that comes in mind is imitating gesture event with a certain velocity, but this sounds horribly wrong.
How about considering an AnimatedList instead.
A scrolling container that animates items when they are inserted or removed.
This widget is similar to one created by ListView.builder.
Please try this.
key: Key(UniqueKey().toString()),
2nd Way
onDismissed: (DismissDirection direction) { dismissViewList(ObjecClass); }
And function is :
dismissViewList(ObjecClass) {
if (_personList.contains(ObjecClass)) {
//_personList is list of ObjecClass shown in ListView
setState(() {
_personList.remove(ObjecClass);
});
}
}