I have listview in my app and in this listView I pull the book titles with API. Book titles are coming up without any problems. But if I press the button more than once, the titles increase as much as I press the button
Here is my code sample
_showData
? Container(
height: MediaQuery.of(context).size.height / 2,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: [
IconButton(
icon: Icon(Icons.close),
onPressed: () {
Navigator.pushNamed(
context, CountryScreen.routeName);
}),
Center(
child: Text(
'Please Select Book',
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 24),
),
),
],
),
Expanded(
child: ListView.builder(
itemCount: bookList.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
onTap: () {
Navigator.pushNamed(
context, MainScreen.routeName);
},
title: Text(bookList[index]),
);
),
],
),
),
)
: SizedBox()
I'm calling my data here,I'm calling in the button
else {
_showData = !_showData;
books.forEach((element) {
bookList.add(element.companyName);
book.setStringList(
'bookName', bookList);
});
}
To illustrate with a small example When I click once on the button I call the data
but if I click twice I see this (the more I click the more it gets), any idea?
The build() method is called whenever there is a change to redraw in the UI. But at that time your bookList state will not be reset.
I will give a trick code to fix this problem:
bookList = [];
books.forEach((element) {
bookList.add(element.companyName);
book.setStringList('bookName', bookList);
});
Related
I have created a sqlite crud application from flutter. my app data insert into the table successfully. but when i show that inserted date from listview need to reload app.in my app data insert from a separate screen. data have shown on home screen. i want show data without reload app in listview how can I slove my problem?
Here is my app code. this is my home screen. this screen show data from listview.
FutureBuilder<List<Student>>(
future: DatabaseHelper.instance.getStudentDetails(),
builder: (BuildContext context,
AsyncSnapshot<List<Student>> snapshot) {
if (!snapshot.hasData) {
return Center(child: Text('Loading...'));
}
return snapshot.data!.isEmpty
? Center(child: Text('No Student Details in List.'))
: ListView(
children: snapshot.data!.map((student) {
return Center(
child: Card(
color: selectedId == student.id
? Colors.white70
: Colors.white,
child: ListTile(
title: Text(
'Student Name : ${student.name}'),
subtitle:
Text('Course : ${student.course}'),
onTap: () {},
onLongPress: () {
setState(() {
DatabaseHelper.instance
.remove(student.id!);
});
},
),
),
);
}).toList(),
);
}),
This is my second screen.this screen I adding data insert into sqlite table.when I click floating action button I want to show insert data in home screen list view without reload.
Column(
children: [
SizedBox(
height: 10.0,
),
Text(
'Enter Student Details',
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Divider(color: Colors.black),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(
label: Text('Enter Name :'),
),
controller: nameController,
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(
label: Text('Enter Course :'),
),
controller: courseController,
),
),
],
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.save),
onPressed: () async {
await DatabaseHelper.instance.add(
Student(name: nameController.text, course: courseController.text),
);
setState(() {
nameController.clear();
courseController.clear();
selectedId = null;
});
},
),
future: DatabaseHelper.instance.getStudentDetails(), will get recall the api on every setState(build).
To avoid recalling the api, create a state variable for this future on state class (outside the build method).
late final future = DatabaseHelper.instance.getStudentDetails();
and use it on FutureBuilder
FutureBuilder<List<Student>>(
future: future,
builder: (BuildContext context,
You can check Fixing a common FutureBuilder and StreamBuilder problem by
Randal L. Schwartz.
int ticket = 0;
List<Painting> paintingList = [
Painting(
title: 'Giacomo Amiconi',
subTitle: 'Jacob and Rachel',
artSubtitle: 'National Museum, Warsaw',
artTitle: '18th Century',
imageAsset:
'https://upload.wikimedia.org/wikipedia/commons/0/0a/Amigoni_Jacob_and_Rachel.jpg',
),
];
return Expanded(
child: ListView.separated(
separatorBuilder: (BuildContext context, int index) {
return SizedBox(height: 10);
},
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: paintingList.length,
itemBuilder: (context, index) {
Painting model = paintingList[index];
return Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 5,
child: Column(
children: [
ListTile(
leading: Padding(
padding: const EdgeInsets.only(top: 8),
child: Icon(Icons.brush, color: orange),
),
title: Text(
model.title!,
style: artTitle,
),
subtitle: Text(
model.subTitle!,
style: artSubtitle,
),
),
Image.network(
model.imageAsset!,
),
ListTile(
title: Text(
model.artTitle!,
style: artTitle,
),
subtitle: Text(
model.artSubtitle!,
style: artSubtitle,
),
trailing: Text('$ticket'),
),
Row(
children: [
Container(
child: GestureDetector(
onTap: () {
setState(() {
ticket++;
});
},
child: Icon(Icons.add)))
],
)
],
)),
);
},
),
);
I created a list named Painting as above and assigned certain values to this list. I didn't add the other 2 Painting() I created to avoid code clutter. I then called the values I created in painting . My goal is to create an add button and increase it each time the user clicks it (like adding a product to the cart). When I do this, yes I can do the augmentation. But the list I create is increasing in all of its elements. I just want to increase or decrease whichever list element I click on the add button next to it.
You can use the insert method of list to add an item at the specific index. See the following example
paintingList.insert(index, paintingList[i]);
Above line will add the same item next to the item that clicked.
Same for removing the item at a specific index you can use removeAt method of list.
paintingList.removeAt(index);
Im trying to remove the scrolling of my ListView widget. Currently, the user only has a small window of tiles to scroll through. The listview data is paged so only shows 20 items at once- i want to show all 20 items and the whole page to scroll, rather than the user scroll through the list view a few at a time. How can i achieve this?
return Column(
children: [
Expanded(
child: ListView.separated(
separatorBuilder: (context, index) => Container(
height: 1,
color: Constants.listSeparatorGrey,
),
itemCount: pageState.data?.data?.length ?? 0,
itemBuilder: (context, idx) =>
itemBuilder(pageState.data?.data?[idx]),
),
),
Text('${pageState.data?.total ?? 0} results',
style: TextStyles.rowHeader(context)),
Text(
'Page ${pageState.data?.currentPage()} of ${pageState.data?.pageNum()}',
style: TextStyles.rowHeader(context),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(width: 20),
if (pageState.data?.hasPrev ?? false)
MyButton(
// isLoading: pageState is Loading,
type: ButtonType.secondary,
label: "Previous",
onPressed: pageApi.prev,
)
else
Container(width: 8),
const SizedBox(
width: 8,
),
(pageState.data?.hasNext ?? false)
? MyButton(
// isLoading: pageState is Loading,
type: ButtonType.secondary,
label: "Next",
onPressed: pageApi.next,
)
: const SizedBox(width: 8)
],
),
],
);
If I correctly understand you. Just move all your content to ListView. So all your page starts scrolling with content.
Widget header = Container(color: Colors.green, height: 100);
List<Widget> content = const [Text("firstCell"), Text("secondCell")];
Widget button =
const TextButton(onPressed: null, child: Text("Next page"));
List<Widget> widgets = [header] + content + [button];
return Scaffold(
appBar: AppBar(
title: const Text('All content in list'),
),
body: ListView(children: widgets),
);
Here result:
All content in ListView
I solved my problem.
I just put the root column in a SingleChildScrollView()
very simple in the end
i have problem with fetch data from database (firestore)
im fetching data from firestore and listing them with listview.builder, when a card is tapped it routes to new page that show all the details of tapped item.
on the screenshot i have 2 item listed with header,body and date when i tapped on item routes to new page and fetch from firestore rest of the data (client,start date,finish date etc.)
my question is what is the best way to fetch tapped items datas
my idea is store somehow items store unique id to the builded item and when it tapped route to new page with id and query with id
my code block
Widget listener(Stream<QuerySnapshot> tasks) {
return Expanded(
child: StreamBuilder<QuerySnapshot>(
stream: tasks,
builder: (
BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot,
) {
if (snapshot.hasError) {
return Center(
child: Text(
"something went wrong.",
style: TextStyle(
color: ColorConstants.instance.headerColor, fontSize: 20),
textAlign: TextAlign.center,
),
);
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.data!.size > 0) {
final data = snapshot.requireData;
return ListView.builder(
itemCount: data.size,
itemBuilder: (context, index) => buildNotificationCards(
context,
data.docs[index]['header'],
data.docs[index]['body'],
data.docs[index]['startDate']));
} else {
return Center(
child: SizedBox(
width: MediaQuery.of(context).size.width * .8,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
LineIcons.fileAlt,
size: 60,
color: ColorConstants.instance.headerColor,
),
SizedBox(
height: 20,
),
Text(
'Maalesef Kayıtlı Bir Veri Bulunamadı',
textAlign: TextAlign.center,
style: TextStyle(
color: ColorConstants.instance.headerColor,
fontSize: 20,
height: 2),
),
]),
),
);
}
},
));
}
The normal practice is under ListView.builder, you create a ListTile and on its onTap argument, you use the Navigator to switch to another page for the detail view:
onTap: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => DetailPage(data[index])),
);
where data[index] is the particular element of the data list you want to display the contents of.
Is there any other way for me to align the text within the leading and title of a ListTile without using the Row widget? The data was fetched from Firebase and then being viewed using Listview. Builder.
FutureBuilder(
future: fetchData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<taskData> result = snapshot.data as List<taskData>;
return ListView.builder(
scrollDirection: Axis.vertical,
itemCount: result.length,
itemBuilder: (BuildContext context, int i) {
DateTime updateDate = DateTime.fromMillisecondsSinceEpoch(result[i].date);
String formDate = DateFormat('yMMMd').format(updateDate);
return GestureDetector(
onTap: () {
NavigationController(context, 'Edit', 'Title',
result[i].task, result[i].id, updateDate);
},
child: Card(
child: ListTile(
leading: Text(formDate, style: TextStyle(fontFamily: 'ProximaNova', fontSize: 16),),
title: Text('${result[i].task}',style: TextStyle(fontFamily: 'ProximaNova',fontSize: 18),),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
id = result[i].id;
showDialog<void>(
context: context, builder: (context) => dialog);
},
),
),
),
);
});
} else if (snapshot.hasError) {
print('${snapshot.error}');
return Text(
"",
style: TextStyle(fontSize: 20),
);
}
// By default, show a loading spinner.
return Center(
child: Container(
margin: EdgeInsets.symmetric(vertical: 100.0),
child: CircularProgressIndicator(),
));
},
),
Here is the picture for reference ('title' is not aligned with 'leading' and 'trailing'):
It is working for you
ListTile(
leading: Text('2021-04-27'),
title: Text('Lion', textAlign: TextAlign.center,),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {},
),
),
Sorry if I'm not solving the problem asked but as a suggestion how about wrapping it in a Row Widget instead of a List Tile where you center align it?
first of all i believe you leading is not aligned with title and trailing, i do not know due to what reason this is happening from your code. solution might be Put your both text in title with + operator. or in leading whichever helps your problem get solved.