Flutter enable mutliselection of tabs of Gridview - dart

I want to enable multiselection functionality for my GridView, but I when I click on any tile all the tiles get automatically selected, I want to enable the tile selected and deselected on tile click. Please help to select and deselect multiple tabs.
Here is code:
void toggleSelection() {
setState(() {
if (_isSelected) {
// mycolor=Colors.white;
_textColor = Colors.deepOrange[400];
_borderColor = Colors.deepOrange[300].withOpacity(0.8);
_isSelected = false;
} else {
// mycolor=Colors.grey[300];
_textColor = Colors.black;
_borderColor = Colors.white;
_isSelected = true;
}
});
}
List<Widget> _getTiles() {
final List<Widget> tiles = <Widget>[];
for (int i = 0; i < listResponseData.length; i++) {
bool isSelected = _serviceindex == i;
tiles.add(Container(
//decoration: BoxDecoration(borderRadius: BorderRadius.circular(6), color: Colors.grey),
child: ListTile(
selected: _isSelected,
title: new GestureDetector(
child: new Card(
elevation: 5.0,
child: new Container(
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
border: Border.all(color: _borderColor),
color: Colors.white,
),
child: new Text(listResponseData[i].nativeText,
style: TextStyle(fontSize: 20, color: _textColor),
),
),
),
onTap: () {
toggleSelection();
},
),
),
));
}
return tiles;
}

I've resolved this issue, here is the working code.
List<ResultResponse> newListResponse = new List();
class ResultResponse {
int id;
String name;
String nativeText;
String image;
bool isSelected;
ResultResponse(this.id, this.name, this.nativeText,
this.image, this.isSelected);
}
List<Widget> _getTiles() {
final List<Widget> tiles = <Widget>[];
for (int i = 0; i < newListResponse.length; i++) {
//_isSelected = _serviceindex == i;
tiles.add(Container(
//decoration: BoxDecoration(borderRadius: BorderRadius.circular(6), color: Colors.grey),
child: ListTile(
title: new GestureDetector(
child: new Card(
elevation: 5.0,
child: new Container(
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
border: Border.all(color: newListResponse[i].isSelected ?
Colors.deepOrange[300].withOpacity(0.8) : Colors.white),
color: Colors.white,
),
child: new Text(newListResponse[i].nativeText,
style: TextStyle(fontSize: 20,
color: newListResponse[i].isSelected
? Colors.deepOrange[400] : Colors.black ),
),
),
),
onTap: () {
toggleSelection( i);
},
),
),
));
}
return tiles;
}
void toggleSelection( int i) {
for(int j=0;j<newListResponse.length; j++)
print(newListResponse[j].isSelected);
setState(() {
if (newListResponse[i].isSelected) {
listSelectedServices.remove(i);
newListResponse[i].isSelected = false;
} else {
listSelectedServices.add(i);
newListResponse[i].isSelected = true;
}
});
}

Related

I want to highlight RED the timeslot that is already in the array clickedDateTime

When I click "SELECT ALL BUTTON", I want to highlight all currently shown buttons.
The desired timeslots are already in clickedDateTime
Console Log
but the buttons of timeslots are not changing color to red as I intended to
Problem:
expected output(I want it to be like this):
import 'package:flutter/material.dart';
import 'package:hoopers/widgets/textTheme.dart';
class RegistrationCalendarScheduling extends StatefulWidget {
List clickedDateTime;
int currentMonth = 0; // load current month
int currentDay = 0; // load current day
int currentAddYear = 0;
int currentAddMonth = 0;
int currentAddDay = 0;
RegistrationCalendarScheduling(this.clickedDateTime, {Key? key}) : super(key: key){
var now = DateTime.now();
currentMonth = now.month-1;
currentDay = now.day-1;
currentAddYear = now.year;
currentAddMonth = now.month;
currentAddDay = now.day;
}
List months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
List days = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31'];
//implement disabled property for buttons?
List time = [5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
//Dummy Data [API] : These are the schedules already taken.
//TO DO: Create a function that checks if the schedule is already taken
List currentClicked = [];
#override
_RegistrationCalendarSchedulingState createState() => _RegistrationCalendarSchedulingState();
}
class _RegistrationCalendarSchedulingState extends State<RegistrationCalendarScheduling> {
int dateChecker (int currentMonth) {
if (currentMonth == 1) {
return 28;
}
else if (currentMonth == 3 || currentMonth == 5 || currentMonth == 8 || currentMonth == 10 ) {
return 30;
}
else {
return 31;
}
}
String format (int item) {
if (item+1 < 10) {
return ("0"+(item+1).toString());
}
return((item+1).toString());
}
Future<void> _selectAllTime() async {
var year = widget.currentAddYear;
var month = format(widget.currentMonth);
var day = format(widget.currentDay);
for (int i = 0; i < widget.time.length; i++) {
String date = year.toString() +
"-" + month.toString() +
"-" + day.toString() +
"-" + widget.time[i].toString();
// log(date);
if (! widget.clickedDateTime.contains(date)) {
widget.clickedDateTime.add(date);
// String item;
// String clickedDateTime;
// List clickedDates;
calendarTimeButton(widget.time[i].toString(), date, widget.clickedDateTime).isClicked(widget.clickedDateTime, date);
// this.isClicked(clickedDates, date);
// RegistrationCalendarScheduling(const []).clickedDateTime!.add(date);
} else {
widget.clickedDateTime.remove(date);
}
}
// setState(() {
// calendarTimeButton(widget.time.toString(),
// '',
// widget.clickedDateTime!,
// widget.currentYear,
// widget.currentAddMonth,
// widget.currentAddDay,
// ).addAllTime(widget.clickedDateTime!);
// });
}
#override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.fromLTRB(10, 30, 10, 10),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
icon: const Icon(Icons.arrow_back_ios_sharp, color: Colors.red),
onPressed:(){
widget.currentMonth == 0? widget.currentMonth = 0 : setState((){
widget.currentMonth -=1;
widget.currentDay = 0;
});
widget.currentAddMonth == 0? widget.currentAddMonth = 0 : setState((){
widget.currentAddMonth -=1;
widget.currentDay = 0;
});
},
),
textTheme(widget.months[widget.currentMonth], 25, Colors.red, 'ZingRust'),
IconButton(
icon: const Icon(Icons.arrow_forward_ios_sharp, color: Colors.red),
onPressed:(){
widget.currentMonth == 11? widget.currentMonth = 11 : setState((){
widget.currentMonth +=1;
widget.currentDay = 0;
});
widget.currentAddMonth == 11? widget.currentAddMonth = 11 : setState((){
widget.currentAddMonth +=1;
widget.currentDay = 0;
});
},
)
],
),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.all(10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: widget.days.sublist(0, dateChecker(widget.currentMonth)).map((item) =>
widget.currentDay == widget.days.indexOf(item) ? InkWell(
onTap: (){},
child: Container(
height: MediaQuery.of(context).size.height * 0.05,
padding: const EdgeInsets.fromLTRB(15, 0, 10, 10),
child: textTheme(item, 17, Colors.red, 'PoppinsRegular')
)
) : InkWell(
onTap: (){
setState(() {
widget.currentDay = widget.days.indexOf(item);
widget.currentAddDay = widget.days.indexOf(item);
});
},
child: Container(
height: MediaQuery.of(context).size.height * 0.05,
padding: const EdgeInsets.fromLTRB(15, 0, 10, 10),
child: textTheme(item, 17, Colors.black, 'PoppinsRegular')
)
)
).toList(),
),
),
Container(
width: double.infinity,
padding: const EdgeInsets.fromLTRB(0, 5, 0, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: widget.time.sublist(0,4).map((item) => calendarTimeButton(item.toString(), "2022-"+ format(widget.currentMonth) + "-"+format(widget.currentDay)+"-"+item.toString(), widget.clickedDateTime)).toList(),
),
),
Container(
width: double.infinity,
padding: const EdgeInsets.fromLTRB(0, 10, 0, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: widget.time.sublist(4,8).map((item) => calendarTimeButton(item.toString(), "2022-"+format(widget.currentMonth)+ "-"+format(widget.currentDay)+"-"+item.toString(), widget.clickedDateTime)).toList(),
),
),
Container(
width: double.infinity,
padding: const EdgeInsets.fromLTRB(0, 10, 0, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: widget.time.sublist(8,12).map((item) => calendarTimeButton(item.toString(), "2022-"+format(widget.currentMonth)+"-"+format(widget.currentDay)+"-"+ item.toString(), widget.clickedDateTime)).toList(),
),
),
Container(
width: double.infinity,
padding: const EdgeInsets.fromLTRB(0, 10, 0, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: widget.time.sublist(12,16).map((item) => calendarTimeButton(item.toString(),"2022-"+format(widget.currentMonth)+"-"+format(widget.currentDay)+"-"+ item.toString(), widget.clickedDateTime)).toList(),
),
),
Container(
width: double.infinity,
padding: const EdgeInsets.fromLTRB(0, 10, 0, 0),
child: MaterialButton(
height: MediaQuery.of(context).size.height * 0.03,
minWidth: double.infinity,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18)),
onPressed: _selectAllTime,
child: const Text(
"Select All",
style: TextStyle(
fontSize: 20,
fontFamily: 'ZingRust',
color: Colors.white,
),
),
color: Colors.red),
),
],
),
);
}
}
//pass a function that would get the current time, day, and month when button is clicked.
class calendarTimeButton extends StatefulWidget {
String item;
String clickedDateTime;
List clickedDates;
calendarTimeButton(this.item,this.clickedDateTime, this.clickedDates, {Key? key}) : super(key: key);
bool isAvailable(){
// for(int i=0; i<availableDates.length; i++){
// if(availableDates[i]['sched'] == clickedDateTime && availableDates[i]['availability'] == "-1"){
return true;
// }
// }
// return false;
}
bool isClicked (List clickedDates, String newClickedDate) {
return clickedDates.contains(newClickedDate);
}
bool check (List clickedDates, String newClickedDate) {
return clickedDates.contains(newClickedDate);
}
void deleteClickedDate(List clickedDates, String newClickedDate){
if(clickedDates.contains(newClickedDate)){
clickedDates.remove(newClickedDate);
}
}
void addClickedDate(List clickedDates, String newClickedDate){
clickedDates.add(newClickedDate);
}
#override
State<calendarTimeButton> createState() => _calendarTimeButtonState();
}
class _calendarTimeButtonState extends State<calendarTimeButton> {
#override
Widget build(BuildContext context) {
return SizedBox(
height: MediaQuery.of(context).size.height * 0.05,
width: MediaQuery.of(context).size.width * 0.19,
child: InkWell(
onTap: () {
setState(() {
if (widget.isAvailable()) {
widget.isClicked(widget.clickedDates, widget.clickedDateTime)
? widget.deleteClickedDate(
widget.clickedDates, widget.clickedDateTime)
: widget.addClickedDate(
widget.clickedDates, widget.clickedDateTime);
}
});
},
child: Card(
// widget.clickedDates, widget.clickedDateTime
color: widget.isAvailable()
? (widget.clickedDates.contains(widget.clickedDateTime)
? Colors.red
: Colors.white)
: Colors.grey[500],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
child: Center(
child: textTheme(
widget.item + ":00", 13, Colors.black, 'PoppinsRegular')),
elevation: 5,
),
),
);
}
}
I feel so embarassed now. I just change line 200 to
onPressed: () {
setState(() {
_selectAllTime();
});
},

Paint on Image after Image loaded from the network

I'm loading the images from api call and then showing the image and some data in listview in flutter and drawing bounding box on image, but since my image is getting loaded from url my UI gets disturbed,How I ensure that the Canvas will paint after the image is loaded from the network url in flutter layout.Is there any callbacks which I can use.
class ListPage extends StatefulWidget {
ListPage({Key key, this.title}) : super(key: key);
final String title;
#override
_ListPageState createState() => _ListPageState();
}
class _ListPageState extends State<ListPage> {
Future<List<ProcessedInference>> processInference;
#override
void initState() {
processInference = localInference();
super.initState();
}
#override
Widget build(BuildContext context) {
final toAppBar = AppBar(
elevation: 0.1,
backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
title: Text(widget.title),
actions: <Widget>[
IconButton(
icon: Icon(Icons.list),
onPressed: () {},
)
],
);
Card makeCard(ProcessedInference pro) => Card(
elevation: 2.0,
margin: new EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0),
child: Container(
child: Column(
children: <Widget>[
CustomPaint(
size: Size(640.0, 480.0),
foregroundPainter: RectPainter(pro.boundingBox),
child: Image.network(pro.frameUrl),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(
height: 8.0,
),
Text(
"Spotted: ${pro.peopleCount}",
style: TextStyle(fontSize: 16.0),
textAlign: TextAlign.start,
),
SizedBox(
height: 8.0,
),
Text(
"Spotted on : ${pro.timeStamp}",
style: TextStyle(fontSize: 16.0),
textAlign: TextAlign.start,
),
SizedBox(
height: 8.0,
),
],
),
],
),
),
);
final makeBody = Container(
child: FutureBuilder<List<ProcessedInference>>(
future: processInference,
builder: (context, snapshot) {
if (snapshot.hasData) {
print("Has data");
if (snapshot.data == null || snapshot.data.length <= 0) {
return Center(
child: Text("No results", textAlign: TextAlign.center));
} else {
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return makeCard(snapshot.data[index]);
});
}
} else if (snapshot.hasError) {
print("has error ");
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
),
);
return Scaffold(
appBar: toAppBar,
body: makeBody,
);
}
}
class RectPainter extends CustomPainter {
final List<List<double>> boundingBox;
RectPainter(this.boundingBox);
#override
void paint(Canvas canvas, Size size) {
final paint = Paint();
paint.color = Colors.deepOrange;
paint.style = PaintingStyle.stroke;
paint.strokeWidth = 2.0;
final boxPaint = Paint();
boxPaint.color = Colors.amberAccent;
boxPaint.style = PaintingStyle.fill;
boxPaint.strokeWidth = 2.0;
for (var i = 0; i < boundingBox.length; i++) {
var confidence = boundingBox[i][0];
var left = boundingBox[i][1] * size.width;
var top = boundingBox[i][2] * size.height;
var right = boundingBox[i][3] * size.width;
var bottom = boundingBox[i][4] * size.height;
var rect = Rect.fromLTRB(left, top - 15, right, bottom);
canvas.drawRect(rect, paint);
TextSpan span = new TextSpan(
style: new TextStyle(color: Colors.red[600], fontSize: 10.0),
text: confidence.toStringAsFixed(2));
TextPainter tp = new TextPainter(
text: span,
textAlign: TextAlign.center,
textDirection: TextDirection.ltr);
tp.layout();
canvas.drawRect(
Rect.fromLTRB(
rect.left, rect.top, rect.left + tp.width, rect.top + tp.height),
boxPaint);
tp.paint(canvas, new Offset(rect.left, rect.top));
}
}
#override
bool shouldRepaint(CustomPainter oldDelegate) {
return false;
}
}

Container icons changes for all on selection one

I am new to flutter this is my problem,
When I select an icon, I am selecting all the other item in the container
I am not able to change the color of container to green when selected
not only on icon but also on container function onpressed
class _AddEmpToProjectState extends State<AddEmpToProject> {
bool _isSelected = false;
Container addEmpListTile() {
return Container(
margin: EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 10.0),
padding: EdgeInsets.all(5.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0), color: Colors.white),
child: Container(
child: ListTile(
leading: CircleAvatar(
backgroundImage: AssetImage('assets/tom.jpg'),
),
title: Text('Sam'),
subtitle: Text('Site Manager'),
trailing: InkWell(
onTap: () {
_isSelected = !_isSelected;
setState(() {});
},
child: _isSelected
? Icon(
Icons.done,
color: Colors.green,
size: 35.0,
)
: Icon(
Icons.add,
color: Colors.deepPurple,
size: 35.0,
))),
));
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.deepPurple,
appBar: AppBar(
title: Text('Add Employees'),
elevation: 0.0,
actions: <Widget>[
IconButton(
icon: Icon(
Icons.search,
color: Colors.white,
),
onPressed: () {},
),
IconButton(
icon: Icon(
Icons.done,
color: Colors.white,
),
onPressed: () {},
)
],
),
body: ListView.builder(
itemCount: 10,
itemBuilder: (BuildContext context, int index) {
return addEmpListTile();
},
),
);
}
}
when container is tapped change color to green and should move to top
if deselected must return back to the array widget index
this is what i am expected to do
Need to track in some way which item is selected (some sort of identifier), not only the fact that an item is selected (boolean).
One solution can be to use index as tracking number
class _AddEmpToProjectState extends State<AddEmpToProject> {
-bool _isSelected = false;
+Set<int> _selected = Set();
...
class _AddEmpToProjectState extends State<AddEmpToProject> {
Set<int> _selected = Set();
Container addEmpListTile(int index) {
...
onTap: () {
setState(() {
if(_selected.contains(index)) {
_selected.remove(index);
} else {
_selected.remove(index);
};
}
},
child: _selected.contains(index)
? Icon(Icons.done)
: Icon(Icons.add)
}
...
build() {
...
itemBuilder: (BuildContext context, int index) {
return addEmpListTile(index); // <-- add index here
...
}

Is there a way to convert Future<List<String>> to List<dynamic>?

Edit:
Home Page - I'm fetching a list of strings from my firebase collection. I then want to make a call to firestore storage and get the downloadable image link and store it in a list that I will pass to Page 2. The code below is how i'm getting the downloadable links.
Future<List<String>> test(List images) async{
List<String> listOfImages = List<String>();
for(int i = 0; i < images.length; i++){
final ref = FirebaseStorage.instance.ref().child(images[i]);
var url = await ref.getDownloadURL();
listOfImages.add(url);
}
return listOfImages;
}
I'm then passing the list of Images in the following manner
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CarDetailScreen(
carImages: test( car['images'])
)),
);
Page 2 - I'm receiving a Future> that I would like to convert to a List
List<T> map<T>(List list, Function handler) {
List<T> result = [];
for (var i = 0; i < list.length; i++) {
result.add(handler(i, list[i]));
}
return result;
}
new CarouselSlider(
items: ***["This is where I need a List"]***.map((url) {
return new Container(
margin: new EdgeInsets.all(5.0),
child:
new GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ViewCarImages(
carImages: _getImages(snapshot))),
);
},
child:
new ClipRRect(
borderRadius: new BorderRadius.all(new Radius.circular(5.0)),
child:
new Image.network(
url,
fit: BoxFit.cover,
width: 1000.0,
)
)
)
);
}).toList(),
viewportFraction: 0.9,
aspectRatio: 2.0,
autoPlay: false,
)
You can just return a List of Widget, like this:
Future<List<Widget>> test(List images) async{
List<Widget> listOfImages = List<Widget>();
for(int i = 0; i < images.length; i++){
final ref = FirebaseStorage.instance.ref().child(images[i]);
var url = await ref.getDownloadURL();
listOfImages.add(Image.network(url));
}
return listOfImages;
}
Below code will solve your problem. In carouselSlide class(check items variable) written below and you need to follow below procedure to work the Future object in carousel
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
backgroundColor: Colors.white,
title: Text("some text",
style: TextStyle(
fontWeight: FontWeight.normal,
color: Colors.black,
fontSize: 16.0)),
centerTitle: false,
actions: <Widget>[
IconButton(
tooltip: 'Search something',
icon: Icon(
Icons.search,
color: SharedColor().sapphireDarkBlue,
),
onPressed: () async {
var selected = await showSearch<int>(
context: context, delegate: _delegate);
if (selected != null && selected != _lastIntegerSelected) {
setState(() {
//pass the data from searchfield query to here
});
}
},
),
],
automaticallyImplyLeading: false,
),
body: _carouselBuild(),
);
}
FutureBuilder<caraouselImage> _carouselBuild() {
return FutureBuilder<caraouselImage>(
future: ImageRestApiManager().caraouselImage(myEmail),
builder: (context, AsyncSnapshot<caraouselImage> snapshot) {
if (snapshot.hasData) {
return CarouselSlider(
items: snapshot.data.collection.map((i) {
return Builder(builder: (BuildContext context) {
return Container(
margin: EdgeInsets.all(5.0),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
child: Stack(children: <Widget>[
Image.network(i.imageurl,
fit: BoxFit.cover, width: 1000.0),
Positioned(
bottom: 0.0,
left: 0.0,
right: 0.0,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Color.fromARGB(200, 0, 0, 0),
Color.fromARGB(0, 0, 0, 0)
],
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
),
),
padding: EdgeInsets.symmetric(
vertical: 10.0, horizontal: 20.0),
child: Text(
_currentCookieSelected.toString(),
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
),
),
]),
),
);
});
}).toList(),
autoPlay: false,
enlargeCenterPage: true,
viewportFraction: 0.9,
aspectRatio: 2.0,
onPageChanged: (index) {
setState(() {
_currentImageSelected = snapshot.data.collection[index].id;
});
});
} else {
return CircularProgressIndicator();
}
});
}
}
I solved using below youtube tutorial
https://www.youtube.com/watch?v=xBLtPDHvT44
A FutureBuilder should get you wht you're looking for. Here, I've wrapped your CarouselSlider in a FutureBuilder, and have the future property set to your carImages Future. When your list of Strings is ready, the FutureBuilder will create the CarouselSlider via its builder method, and all of the list items will be present then:
return FutureBuilder<List<String>>(
future: carImages,
initialData: [],
builder: (context, snapshot) {
return new CarouselSlider(
viewportFraction: 0.9,
aspectRatio: 2.0,
autoPlay: false,
items: snapshot.data.map((url) {
return new Container(
margin: new EdgeInsets.all(5.0),
child:
new GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ViewCarImages(
carImages: _getImages(snapshot))),
);
},
child: new ClipRRect(
borderRadius: new BorderRadius.all(new Radius.circular(5.0)),
child: new Image.network(
url,
fit: BoxFit.cover,
width: 1000.0,
)
)
)
);
}).toList(),
);
}
);

Flutter - widget testing for the Cupertino picker in flutter/Dart

i am testing the Cupertino picker,for which i am writing widget testing and i am struggling to implement how the onselectItemChanged in testing and accordingly the values chosen by the wheeling of the cupertino picker. The testing has to be done so that the value when user chooses accordingly the test case has to written in such a way that it suits to different values chosen
List<String> ages1 = ["-- select --"];
List<String> ages2 = List<String>.generate(
45, (int index) => (21 + index).toString(),
growable: false);
List<String> ages = [ages1, ages2].expand((f) => f).toList();
picker.dart:
Widget _buildAgePicker(BuildContext context) {
final FixedExtentScrollController scrollController =
FixedExtentScrollController(initialItem: _selectedAgeIndex);
return GestureDetector(
key: Key("Age Picker"),
onTap: () async {
await showCupertinoModalPopup<void>(
context: context,
builder: (BuildContext context) {
return _buildBottomPicker(
CupertinoPicker(
key: Key("Age picker"),
scrollController: scrollController,
itemExtent: dropDownPickerItemHeight,
backgroundColor: Theme.of(context).canvasColor,
onSelectedItemChanged: (int index) {
setState(() {
_selectedAgeIndex = index;
ageValue = ages[index];
if (ageValue == S.of(context).pickerDefaultValue) {
ageDividerColor = Theme.of(context).errorColor;
errorText = S.of(context).pickerErrorMessage;
ageDividerWidth = 1.2;
} else {
ageDividerColor = Colors.black87;
errorText = "";
ageDividerWidth = 0.4;
}
});
},
children: List<Widget>.generate(ages.length, (int index) {
return Center(
child: Text(ages[index]),
);
}),
),
);
},
);
},
child: _buildMenu(
<Widget>[
Text(
S.of(context).Age,
style: TextStyle(fontSize: 17.0),
),
Text(
ages[_selectedAgeIndex],
),
],
),
);
}
Widget _buildMenu(List<Widget> children) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).canvasColor,
),
height: 44.0,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: SafeArea(
top: false,
bottom: false,
child: DefaultTextStyle(
style: const TextStyle(
color: Colors.black,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: children,
),
),
),
),
);
}
Widget _buildBottomPicker(Widget picker) {
return Container(
height: dropDownPickerSheetHeight,
padding: const EdgeInsets.only(top: 6.0),
color: Theme.of(context).canvasColor,
child: DefaultTextStyle(
style: const TextStyle(
color: Colors.black,
fontSize: 22.0,
),
child: GestureDetector(
key: Key("picker"),
onTap: () {},
child: SafeArea(
top: false,
child: picker,
),
),
),
);
}
widget_test.dart:
testWidgets("picker test",(WidgetTester tester)async{
await tester.tap(find.byKey(Key("Age Picker")));
await tester.drag(find.byKey(Key("Age Picker")), Offset(0.0,70.0));
await tester.pumpAndSettle();
expect(ages[1], "21");
});

Resources