Flutter: how to add more values on screen - flutter

I am 9 displaying values of each employee from table.
Tried with Listview with row with containers, onSelect is taking more space and not looking good.
ListTiles but not able to fit all values.
Could you suggest best practices?
body: SafeArea(
child: Container(
child: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: contacts.length,
itemBuilder: (BuildContext context, int index) {
// return item
return ContactItem(
contacts[index].name,
contacts[index].phoneNumber,
contacts[index].isSelected,
index,
Widget ContactItem(
String name, String phoneNumber, bool isSelected, int index) {
return ListTile(
title: Text(
name,
style: TextStyle(
fontWeight: FontWeight.w500,
),
),
//subtitle: Text(phoneNumber),
subtitle: Text('$phoneNumber' '\n' '$phoneNumber'),
isThreeLine: true,
leading: isSelected
? Icon(
Icons.check_circle,
color: Colors.green[700],
)
: Icon(
Icons.check_circle_outline,
color: Colors.grey,
),
onTap: () {
setState(() {
contacts[index].isSelected = !contacts[index].isSelected;
if (contacts[index].isSelected == true) {
selectedContacts.add(ContactModel(name, phoneNumber, true));
} else if (contacts[index].isSelected == false) {
selectedContacts.removeWhere(
(element) => element.name == contacts[index].name);
}
});
},
));

Related

Flutter SwitchListTile Changing State on AllItems

I am trying to use the SwitchTileList to show all my categories and toggle them on/off however it seems to either not change state/toggle or it will toggle all of them together.
At the moment the code below the showdefault items are on as should be and the rest are off, however it will not toggle any of them at the moment.
return FutureBuilder(
future: amenityCategories,
builder:
(BuildContext context, AsyncSnapshot<AmenityCategories> snapshot) {
if (snapshot.hasData) {
return ListView(
padding: EdgeInsets.zero,
children: [
SizedBox(
height: 85.0,
child: DrawerHeader(
child: Text(
'Show/Hide Map Pins',
style: new TextStyle(fontSize: 18.0, color: Colors.white),
),
decoration: const BoxDecoration(
color: Colors.green,
),
),
),
SizedBox(
height: double.maxFinite,
child: ListView.builder(
itemCount: snapshot.data!.categories.length,
itemBuilder: (context, index) {
bool toggle = false;
if (snapshot.data!.categories[index].showbydefault == 1) {
toggle = true;
}
return SwitchListTile(
title: Text(
snapshot.data!.categories[index].categoryname),
value: toggle,
onChanged: (bool val) {
if (val != toggle) {
setState(() {
toggle = !toggle;
});
}
});
},
),
),
],
);
}
return Container();
});
}
You must use a separate variable for each individual ListTile. Give your category an additional variable isActive and work with it.
onChanged: (bool val) {
if (val != snapshot.data!.categories[index].isActive) {
setState(() {
snapshot.data!.categories[index].isActive = !snapshot.data!.categories[index].isActive;
});
}

dynamically created checkbox dart/flutter

I am trying to dynamically create some checkboxes based on data pulled from an API. My checkboxes are created but when I click on them they are all being checked or unchecked.
I am pretty sure I can identify why I am getting is, I am just unsure how to overcome it.
The variable I create is for one check box, so when my list is created from ListView.builder, it is using the same variable thereby making all boxes check and uncheck. I know that I need to create that variable based on how many items are in the list. I am just not sure how to do this and where within my code structure. I tried different methods of using .length or trying to use a .forEach but none of it was correct in the method I was implementing it. I have included my code that shows how I am creating my list of tags.
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:gateway_device/backend/api/api_services.dart';
import 'package:gateway_device/flutter_flow/flutter_flow_theme.dart';
import 'package:gateway_device/models/tag_list_model.dart';
class TagsListWidget extends StatefulWidget {
final int companyId;
const TagsListWidget({Key? key, required this.companyId}) : super(key: key);
#override
State<TagsListWidget> createState() => _TagsListWidgetState(companyId);
}
class _TagsListWidgetState extends State<TagsListWidget> {
final int companyId;
late bool checkboxListTileValue = false;
final scaffoldKey = GlobalKey<ScaffoldState>();
_TagsListWidgetState(this.companyId);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Tags",
textAlign: TextAlign.center,
style: FlutterFlowTheme.of(context).title2.override(
fontFamily: 'Heebo',
fontSize: 18.sp,
fontWeight: FontWeight.w500),
),
elevation: 0,
actions: <Widget>[
IconButton(
hoverColor: Colors.transparent,
iconSize: 40,
icon: Icon(
Icons.search,
color: Colors.black,
size: 20,
),
onPressed: () {
print("Test");
},
)
],
leading: IconButton(
hoverColor: Colors.transparent,
iconSize: 40,
icon: Icon(
Icons.keyboard_return_sharp,
color: Colors.black,
size: 30,
),
onPressed: () {
Navigator.pop(context);
},
),
centerTitle: true,
backgroundColor: Colors.white,
iconTheme: IconThemeData(color: Colors.black),
),
backgroundColor: Colors.white,
body: SafeArea(
child: FutureBuilder(
future: ApiService().getTagList(companyId),
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
Tags tags = snapshot.data[index];
return GestureDetector(
onTap: (() {
FocusScope.of(context).unfocus();
}),
child: Center(
child: CheckboxListTile(
value: checkboxListTileValue,
onChanged: (newValue) => setState(() {
checkboxListTileValue = newValue!;
}),
title: Text(tags.tag,
textAlign: TextAlign.start,
style: FlutterFlowTheme.of(context)
.title3
.override(
fontFamily: 'Heebo',
color: Colors.black,
fontSize: 18.sp)),
),
),
);
});
}
return Center(
child: CircularProgressIndicator(),
);
}),
),
);
}
}
I appreciate the help!
You can create List:
List<bool> checkboxValue = [];
then use it like this:
return StatefulBuilder(// add this
builder: (c, innerSetState) {
return GestureDetector(
onTap: (() {
FocusScope.of(context).unfocus();
}),
child: ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
Tags tags = snapshot.data[index];
checkboxValue = List<bool>.generate(snapshot.data.length,(counter) => false); // add this
return GestureDetector(
onTap: (() {
FocusScope.of(context).unfocus();
}),
child: Center(
child: CheckboxListTile(
value: checkboxValue[index], //add this
onChanged: (newValue) {
innerSetState(() {// add this
checkboxValue[index] = newValue;
});
},
title: Text(tags.tag,
textAlign: TextAlign.start,
style: FlutterFlowTheme.of(context)
.title3
.override(
fontFamily: 'Heebo',
color: Colors.black,
fontSize: 18.sp)),
),
),
);
}),
);
},
);
note that this work when checkbox value not come from api, if it is let me know so I can Update my answer.
Here is the problem, that you use varieble checkboxListTileValue in global scope. Then yo set new value in:
onChanged: (newValue) => setState(() {
checkboxListTileValue = newValue!;})
Global checkboxListTileValue applayed to all ListView items.
You can made the List checkboxListTileValue, with defaul value set. And onChage set the new value only for item with index which was clicked.
onChanged: (newValue) => setState(() {
checkboxListTileValue[index] = newValue!;})
You are using single bool to control the checked status of a list. You can create a model class with a bool filed that will be like bool isCheked=false , Once you click on item check it is already checked or not and change the value.
Or create a List that will hold tags.tag value.
List<String> selected = [];
....
value: selected.contains(tags.tag),
onChanged: (newValue)
{
if(selected.contains(tags.tag)){
selected.remove(tags.tag); }
else{
selected.add(tags.tag);
}
setState((){});

How to get the items from list according to id in flutter?

Requirement:
I created a list of days using CheckboxlistTile, and i want when i check any checkbox a button will display, and onclick on button a dialogue will display where user can add time in textfield, and then on click on submit button of dialogue that textfield time input will convert into a tag and will display below the checkbox.
here my screen look like before check the checkbox
initially i set Monday checkbox checked.
so when i click on add button (which in at the right of checkbox), this dialogue will display
and when i enter the values and after clicking on submit button, tag will look like this
Problem:
Problem is, when i check the tuesday or any other checkbox this tag is displaying in its list, wherease i have not selected time for tuesday or any checkbox, i guess the problem is in list which i'm passing to create tags _timingTagListForToken
here is the code:
Days list class
class CheckBoxListTileModelForToken {
int id;
String title;
bool isCheck;
CheckBoxListTileModelForToken({required this.id,required this.title, required this.isCheck});
static List<CheckBoxListTileModelForToken> getUsers() {
return <CheckBoxListTileModelForToken>[
CheckBoxListTileModelForToken(id:1,title: "Monday", isCheck: true,),
CheckBoxListTileModelForToken(id:2,title: "Tuesday", isCheck: false),
CheckBoxListTileModelForToken(id:3,title: "Wednesday", isCheck: false),
CheckBoxListTileModelForToken(id:4,title: "Thursday", isCheck: false),
CheckBoxListTileModelForToken(id:5,title: "Friday", isCheck: false),
CheckBoxListTileModelForToken(id:6,title: "Saturday", isCheck: false),
CheckBoxListTileModelForToken(id:7,title: "Sunday", isCheck: false),
];
}
}
Code where i'm display the Checkboxes
customExpansionTile(context, "Token Distribution Time",
true,
Icon(Icons.timer, color: HexColor("#5344ed")),
<Widget>[
Container(
child: Row(
children: [
Expanded(
child: SizedBox(
height: MediaQuery.of(context).size.height * 0.45,
child: ListTile(
title: ListView.builder(
itemCount: checkBoxListTileModelForToken.length,
itemBuilder: (BuildContext context, int index) {
return new Card(
child: new Container(
padding: new EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
new CheckboxListTile(
controlAffinity:ListTileControlAffinity.leading,
activeColor: HexColor("#5344ed"),
dense: true,
title: new Text(
checkBoxListTileModelForToken[index].title,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
letterSpacing: 0.5),
),
value: checkBoxListTileModelForToken[index].isCheck? true:false,
secondary: Container(
alignment:Alignment.centerRight,
height: MediaQuery.of(context).size.height*0.9,
width: MediaQuery.of(context).size.width *0.2,
child:checkBoxListTileModelForToken[index].isCheck ==true?
IconButton(
tooltip:"Pick Time",
onPressed: () {
_tokenTimeDialogue(
checkBoxListTileModelForToken[index].id);
},
icon: Icon(Icons.add,color: HexColor("#5344ed"),)
)
: null),
onChanged: (bool? val) {
itemChangeforToken(val!, index);
}),
SizedBox10(),
Wrap(
direction:Axis.horizontal,
children:[
Container(
child:checkBoxListTileModelForToken[index].isCheck? Tags(
itemCount:_timingTagListForToken.length,
itemBuilder: (int index){
return ItemTags(
key: Key(index.toString()),
activeColor:HexColor("#5344ed"),
index: index,
title:_timingTagListForToken[index],
textStyle: TextStyle( fontSize: 14, ),
combine: ItemTagsCombine.withTextBefore,
removeButton: ItemTagsRemoveButton(
backgroundColor:HexColor("#5344ed"),
onRemoved: (){
setState(() {
_timingTagListForToken.removeAt(index);
});
return true;
},
),
onPressed: (item) => print(item),
onLongPressed: (item) => print(item),
);
},):Padding(
padding: const EdgeInsets.only(left: 70),
child:
Row(crossAxisAlignment: CrossAxisAlignment.center, children: []))
),
])]),
),
);
}),
))),
itemChangeforToken(bool val, int index) {
setState(() {
//id=checkBoxListTileModelForToken[index].id;
//print("id onchange "+ id.toString());
checkBoxListTileModelForToken[index].isCheck = val;
});
}
Dialogue code
_tokenTimeDialogue(dynamic id) {
AlertDialog alert = AlertDialog(
scrollable: true,
insetPadding: EdgeInsets.symmetric(vertical: 50),
title: Text("Add timing of the day",
style: TextStyle(fontWeight: FontWeight.bold, color: HexColor("#5344ed"))),
content: Container(
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(children: <Widget>[
textfieldforTimeDialogue(
context,
() async {
TimeOfDay? pickedTime = await showTimePicker(
initialTime: TimeOfDay.now(),
context: context,
builder:(context, child) {
return Theme(
data: Theme.of(context).copyWith(
colorScheme: ColorScheme.light(
primary: HexColor(
"#6610f2"), // header background color
onPrimary: Colors.black, // header text color
onSurface: Colors.black, // body text color
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
primary: HexColor(
"#6610f2"), // button text color
),
),
),
child: child!,
);
},
);
if (pickedTime != null) {
setState(() {
fromTimeForToken.text = pickedTime.format(context);
});
} else {
print("Time is not selected");
}
},
Icons.timer_off,
fromTimeForToken,
"From",
"From",
),
SizedBox20(),
textfieldforTimeDialogue(
context,
() async {
FocusScope.of(context).unfocus();
TimeOfDay? pickedTime = await showTimePicker(
initialTime: TimeOfDay.now(),
context: context,
builder:(context, child) {
return Theme(
data: Theme.of(context).copyWith(
colorScheme: ColorScheme.light(
primary: HexColor(
"#6610f2"), // header background color
onPrimary: Colors.black, // header text color
onSurface: Colors.black, // body text color
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
primary: HexColor(
"#6610f2"), // button text color
),
),
),
child: child!,
);
},
);
if (pickedTime != null) {
setState(() {
toTimeForToken.text = pickedTime.format(context);
});
} else {
print("Time is not selected");
}
},
Icons.timer_off,
toTimeForToken,
"To",
"To",
),
]),
)),
actions: [
TextButton(
onPressed: () {
setState(() {
fromTimeForToken.text="";
toTimeForToken.text="";
});
Navigator.pop(context);
},
child: Text(
"Submit",
style: TextStyle(
fontWeight: FontWeight.bold,
color: HexColor("#5344ed"),
fontSize: 20),
),
)
]);
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
please help where i'm doing wrong, how i can do this?
You are right - you handle the tags list wrong. For every Monday, Tuesday etc., you are looping through the entire list.
Something like this should work (I only changed lines 2 and 3 below)
child:checkBoxListTileModelForToken[index].isCheck? Tags(
itemCount:_timingTagListForToken[index]==null?0:1, //show only a single tag for your option
itemBuilder: (int index2){ // here you must rename your variable, since we need access to index in the outer loop
return ItemTags(
key: Key(index.toString()),
activeColor:HexColor("#5344ed"),
index: index,
title:_timingTagListForToken[index],
textStyle: TextStyle( fontSize: 14, ),
combine: ItemTagsCombine.withTextBefore,
removeButton: ItemTagsRemoveButton(
backgroundColor:HexColor("#5344ed"),
onRemoved: (){
setState(() {
_timingTagListForToken.removeAt(index);
});
return true;
},
),
onPressed: (item) => print(item),
onLongPressed: (item) => print(item),
);

Flutter Calendar - Showing custom data on days not works well

I´m using flutter with a calendar carousel (https://pub.dev/packages/flutter_calendar_carousel)
For each day for which there is an entry in the database, I want to display an icon in the calendar. What is the best way to do this?
That´s my current code:
Please check the part with the customDayBuilder
class _CalendarScreenState extends State<CalendarScreen> {
DateTime _currentDate;
openNewEntryDialog(BuildContext context, date) {
setState(() {
_currentDate = date;
});
showBarModalBottomSheet(
context: context,
builder: (BuildContext context, scrollController) {
return AddCalendarEntry(
scrollController: scrollController,
currentDate: _currentDate,
);
});
}
#override
Widget build(BuildContext context) {
final calendarEntriesData = Provider.of<CalendarEntries>(context);
void initState() {
_currentDate = widget._currentDate;
super.initState();
}
dayPressed(date, events) {
this.setState(() => _currentDate = date);
}
return Material(
child: CupertinoPageScaffold(
backgroundColor: Colors.white,
navigationBar: CupertinoNavigationBar(
trailing: IconButton(
icon: Icon(Icons.add),
color: Colors.white,
onPressed: () => openNewEntryDialog(context, DateTime.now())),
middle: Text("Juni 2020",
style: Theme.of(context).appBarTheme.textTheme.headline1),
backgroundColor: Theme.of(context).primaryColor,
),
child: Padding(
padding: const EdgeInsets.only(left: 15.0, right: 15.0),
child: Column(
children: <Widget>[
Expanded(
child: CalendarCarousel(
markedDateIconBorderColor: Theme.of(context).primaryColor,
weekdayTextStyle:
TextStyle(color: Theme.of(context).primaryColor),
daysTextStyle:
TextStyle(color: Theme.of(context).primaryColor),
todayButtonColor: Theme.of(context).primaryColor,
weekendTextStyle: TextStyle(color: Colors.black),
locale: "de",
selectedDayButtonColor: Colors.grey.shade100,
selectedDateTime: _currentDate,
headerTextStyle: TextStyle(
color: Theme.of(context).primaryColor, fontSize: 25),
onDayPressed: (DateTime date, List<Event> events) =>
dayPressed(date, events),
onDayLongPressed: (DateTime date) =>
openNewEntryDialog(context, date),
customDayBuilder: (bool isSelectable,
int index,
bool isSelectedDay,
bool isToday,
bool isPrevMonthDay,
TextStyle textStyle,
bool isNextMonthDay,
bool isThisMonthDay,
DateTime day) {
return FutureBuilder(
future: calendarEntriesData.getAll(),
builder: (BuildContext context,
AsyncSnapshot<List<CalendarEntry>> snapshot) {
if (!snapshot.hasData ||
snapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else {
for (final entry in snapshot.data) {
var temp =
DateTime.parse(entry.dateTime).toUtc();
var d1 = DateTime.utc(
temp.year, temp.month, temp.day);
var d2 = DateTime.utc(
day.year, day.month, day.day);
if (d2.compareTo(d1) == 0) {
return Center(
child: Icon(Icons.local_airport));
}
}
}
});
},
),
),
Expanded(
flex: 1,
child: Container(
margin: EdgeInsets.only(top: 35),
child: FutureBuilder<List<CalendarEntry>>(
future: calendarEntriesData
.getCurrentMonthEntries(_currentDate != null
? _currentDate
: DateTime.now()),
builder: (BuildContext context,
AsyncSnapshot<List<CalendarEntry>> snapshot) {
if (!snapshot.hasData ||
snapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else {
return Container(
height: 100,
child: ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context,
int index) {
return ListTile(
title: Text(snapshot
.data[index].servicePartner
.toString()),
subtitle: snapshot.data[index]
.dateTime ==
null
? Text("Unbekannt")
: Text(DateFormat(
"dd.MM.yyyy")
.format(DateTime.parse(
snapshot.data[index]
.dateTime))),
trailing: Text((snapshot
.data[index]
.minutes /
60)
.toString() +
" Stunden"),
);
}));
}
})))
],
),
)));
}
}
How you can see, I´m using a FutureBuilder to check all database entries. And if a day matches, I show an Icon on this day. This works in general, but
I have some errors on the screen
The performance is very bad, because there is some flickering..for each click on another day the widget renders completely. I don´t want this.
How could I improve my code? How could I do this better?
Thanks so much for your help!
Please use the button and button style for this to generate a clickable.
Also resolved your issue.
Widget renderDay(
bool isSelectable,
int index,
bool isSelectedDay,
//bool isToday,
bool isPrevMonthDay,
TextStyle? textStyle,
TextStyle defaultTextStyle,
bool isNextMonthDay,
bool isThisMonthDay,
DateTime now,
) {
final EventList<T>? markedDatesMap = widget.markedDatesMap;
List<Event> markedEvents =
widget.markedDatesMap!.getEvents(now) as List<Event>? ?? [];
return Container(
child: ElevatedButtonTheme(
data: ElevatedButtonThemeData(
style: ButtonStyle(
side: MaterialStateProperty.resolveWith<BorderSide>((states) =>
BorderSide(
color: ColorConstants.WHITE)),
backgroundColor: MaterialStateProperty.resolveWith<Color>(
(states) => markedEvents.length > 0 &&
!isPrevMonthDay &&
!isNextMonthDay
? _getStatusColor(
markedEvents[0].dayStatus!.toLowerCase())
: isSelectedDay && widget.selectedDayButtonColor != null
? widget.selectedDayButtonColor
: widget.dayButtonColor,
),
shape: MaterialStateProperty.resolveWith<OutlinedBorder>((_) {
return RoundedRectangleBorder(
borderRadius: BorderRadius.circular(80));
}),
textStyle: MaterialStateProperty.resolveWith<TextStyle>(
(states) =>
TextStyle(color: ColorConstants.BUTTON_BG_COLOR)),
padding: MaterialStateProperty.all(
EdgeInsets.all(widget.dayPadding),
),
),
),
child: ElevatedButton(
onPressed:
widget.disableDayPressed ? null : () => _onDayPressed(now),
child: Stack(
children: <Widget>[
getDayContainer(
isSelectable,
index,
isSelectedDay,
// isToday,
isPrevMonthDay,
textStyle,
defaultTextStyle,
isNextMonthDay,
isThisMonthDay,
now),
],
),
),
),
);
}

ListView.builder itemCount not updating inside StreamBuilder

I have a flutter app where a list is generated with ListView.Builder, and where the itemCount is the number of documents in a firestore collection.
When I add a document to the collection I can see that the value snapshot.data.documents.length changes by printing it, but the the itemCount does not change, which causes the following error:
Invalid value: Not in range 0..17, inclusive: 18
Here is a GitHub thread I created about the same problem: https://github.com/flutter/flutter/issues/39206
And here is the code for the page in question, and the list i'm getting the error from is the one in the StreamBuilder close to the bottom:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
/*
Visar kontaktinformation
*/
class Contact extends StatefulWidget {
#override
_ContactState createState() => _ContactState();
}
class _ContactState extends State<Contact> {
_hasDesc(desc) {
if (desc == '') {
return false;
} else {
return true;
}
}
String sortby = 'namn';
bool decending = false;
var showInfo;
TextEditingController controller = new TextEditingController();
String filter;
#override
void initState() {
super.initState();
controller.addListener(() {
setState(() {
filter = controller.text.toLowerCase(); //Gör om till gemener för att inte vara skiftlägeskänslig
});
});
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
Widget _personer(context, DocumentSnapshot document, index) {
//Skapar lista från databasen med kontaktinformation
//Denna lista måste vara i rätt ordning i databasen
final info = List<String>.from(document['info']);
//Om sökrutan är tom visas alla personer, om inte så visas bara de som matchar filtret
if (filter == null ||
filter == '' ||
document['namn'].toLowerCase().contains(filter) ||
document['beskrivning'].toLowerCase().contains(filter)) {
return Column(
children: <Widget>[
ListTile(
onTap: () {
setState(() {
for (int i = 0; i < showInfo.length; i++) {
if (i != index) {
showInfo[i] = false; // för att enbart ett kort ska vara expanderat åt gången
}
}
showInfo[index] = !showInfo[index];
});
},
title: Padding(
padding: const EdgeInsets.fromLTRB(0, 4, 0, 4),
child: Column(
children: <Widget>[
Text(
document['namn'],
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headline,
),
Visibility(
visible: _hasDesc(document['beskrivning']),
child: Text(
document['beskrivning'],
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.subtitle.copyWith(fontSize: 20),
),
),
Visibility(
visible: showInfo[index],
child: ListView.builder(
//Bygger lista med kontaktinfo för varje person
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: info.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.only(top: 5),
child: ButtonTheme(
child: GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(text: info[index]));
//skapar snackbar
final copiedTextSnackBar = SnackBar(
content: Text('"${info[index].replaceAll('/', '')}" har kopierats'),
action: SnackBarAction(
label: 'Okej',
onPressed: () => Scaffold.of(context).hideCurrentSnackBar(),
),
);
//Stänger eventuell snackbar och viar en ny
Scaffold.of(context).hideCurrentSnackBar();
Scaffold.of(context).showSnackBar(copiedTextSnackBar);
},
child: Text(
info[index].replaceAll('/', '\n'),
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.body1.copyWith(
fontSize: 16,
color: Color(0xff555555),
),
),
),
),
);
},
),
),
],
),
),
),
Divider(
color: Colors.black,
),
],
);
} else {
return SizedBox(
height: 0, //Visar ingenting om filtret inte stämmer
);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Row(
children: <Widget>[
Flexible(
child: TextField(
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(20, 10, 20, 10),
hintText: 'Sök',
border: InputBorder.none,
),
controller: controller,
),
),
Text('Sortera: ', style: TextStyle(fontSize: 16, color: Color(0xff555555)),),
DropdownButton<String>(
value: sortby,
onChanged: (String newValue) {
setState(() {
sortby = newValue;
});
},
items: [
DropdownMenuItem(
value: 'namn',
child: Text('Namn'),
),
DropdownMenuItem(
value: 'beskrivning',
child: Text('Titel'),
)
]
),
Stack(
children: <Widget>[
Visibility(
visible: decending,
child: IconButton(
icon: Icon(Icons.arrow_upward),
onPressed: () => setState(() {
decending = false;
}),
),
),
Visibility(
visible: !decending,
child: IconButton(
icon: Icon(Icons.arrow_downward),
onPressed: () => setState(() {
decending = true;
}),
),
)
],
)
],
),
Expanded(
child: Container(
child: StreamBuilder(
stream: Firestore.instance.collection('kontakt').orderBy(sortby, descending: decending).snapshots(), //Hämtar data från databas
builder: (context, snapshot) {
//För att inte skriva över existerande lista:
if (showInfo == null) {
//Listan genereras här för att slippa kalla på databasen två ggr
showInfo = List.generate(snapshot.data.documents.length, (index) => false);
}
if (!snapshot.hasData) {
return Container();
} else if (snapshot.hasData) {
print(snapshot.data.documents.length);
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) =>
_personer(context, snapshot.data.documents[index], index),
);
} else {
return Center(
child: Text("Error"),
);
}
},
),
),
),
],
),
);
}
}
I believe it is because of this line:
if (showInfo == null) {
showInfo = List.generate(snapshot.data.documents.length, (index) => false);
}
the showInfo List only gets updated once due to the condition provided. at first, showInfo is null so it gets updated. On consecutive rebuilds, the List doesn't get updated because it is not equal to null anymore. try removing the if condition and see what happens.