I am having a problem with my lists in flutter not consistently keeping the order that I give them. I have a list: List alphabet = ['a', 'b', 'c', 'd'];, and am trying to display it with ListView.builder like this:
ListView.builder(
shrinkWrap: true,
itemCount: alphabet.length,
itemBuilder: (BuildContext ctxt, int index) {
return Center(
child: Text(alphabet[index]));
})
Usually this displays as "a b c d", but not always, sometimes it loads as "d, a, b, c" which is not acceptable. Once, it even came out as "d, a, c, b". How can I make it load the first way consistently?
I also have this line of code: var letterA = (alphabet).first;. Likewise it usually displays "a" but sometimes will display "d".
I couldn't find anything online about this problem, so I guess it is a silly mistake somewhere. I changed the page that includes the ListView from Stateful to Stateless hoping it would help but it didn't at all. And now I don't know what to do?
I could break up all my lists and write them letter by letter each time but I feel that is not the correct solution to my problem.
Edit:
Both alphabet and letterA are in a dart file together "mylists.dart" that just have that data, and then I imported it into this file:
import 'package:flutter/material.dart';
import 'package:flutterproject/mylists.dart';
import 'package:flutterproject/nextpage.dart';
class AlphabetPage2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: GestureDetector(
onTap: () => Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => NextPage(),
),
),
child: ListView.builder(
shrinkWrap: true,
itemCount: alphabet.length,
itemBuilder: (BuildContext ctxt, int index) {
return Center(
child: Text(alphabet[index]));
})),
),
));
}
}
mylists.dart looks like this:
List alphabet = ['a', 'b', 'c', 'd'];
var letterA = (alphabet).first;
List soups = ['tomato', 'chicken noodle', 'lentil'];
var soupA = (soups).first;
The order, though usually correct is not always correct. And in other pages when I call soupA I mostly get tomato, but sometimes get another one.
Related
I have a searchDelegate and when user searches, I use the list.where to fetch accordingly, now that I have that down, I have an issue where when user doesn't include some characters like a comma or apostrophe or hypen, it doesn't show those results,
EXAMPLE
I have a book in my list with title => 'Tis you I want, O Juliet.
when user searches without the apostrophe, or even misses the comma, it won't show that book unless you type it character for character, I want a case where I can make the where() method ignore the user's ignorance if you get me... here's some code snippet.
import 'package:flutter/material.dart';
import 'book.dart';
import 'book_brain.dart';
class MyDelegate extends SearchDelegate<Book> {
#override
Widget? buildLeading(BuildContext context) {
return IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
Navigator.pop(context);
},
);
}
#override
List<Widget>? buildActions(BuildContext context) {
return [
IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
query.isEmpty ? Navigator.pop(context) : query = '';
},
),
];
}
#override
Widget buildResults(BuildContext context) {
return const Center();
}
#override
Widget buildSuggestions(BuildContext context) {
List<Book> suggestions = BookBrain().allBooks().where((book) {
final result = book.bookText.toLowerCase();
final input = query.toLowerCase();
final result2 = book.bookTitle.toLowerCase();
//here I wanna make it ignore when user misses certain characters
return result.contains(input) || result2.contains(input);
}).toList();
return ListView.builder(
itemCount: suggestions.length,
itemBuilder: (context, suggestIndex) {
final suggestion = suggestions[suggestIndex];
return ListTile(
title: Text(suggestion.bookTitle),
trailing: Text('${suggestion.authorName} ${suggestion.bookYear}',
style: const TextStyle(
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w300,
),
),
onTap: () {
close(context, suggestion);
},
);
});
}
}
You can accomplish this with a regex. result and result2 will have all spaces and special characters removed.
// "It's in 4 hours." -> "itsin4hours"
final result = book.bookText.replaceAll(RegExp('[^A-Za-z0-9]'), '').toLowerCase();
final result2 = book.bookTitle.replaceAll(RegExp('[^A-Za-z0-9]'), '').toLowerCase();
More detailed example here
I'm learning Flutter. I have a ListView and I would like to make the list items clickable. My idea is that when the user clicks on an item, it will be directed to another screen. Each buttom should leads to different screen. I'm having trouble implementing it, I don't know what to use: gesture detector or ontap. What should I do? Should I use ListTile instead of ListView?list viewdata
If you're using a ListView.builder, you can use a ListTile to add an onTap.
ListView.builder(
itemBuilder: (_, i) {
return ListTile(
title: Text('$i'),
onTap: () {}, // Handle your onTap here.
);
},
)
well, you can use Inkwell. ListView.builder( itemBuilder: (_, i) { return InkWell( onTap: (){}, child: ///widget, ); }, ) link enter link description here
hi may i ask how to remove an item from the ListViewBuilder,
normally it must be enough if i have an array let's call it x;
then i can remove any item that i want by using remoteAt
x.removeAt(index);
but in this case i couldn't know exactly how can i do that.
so i don't have an x array or list in this case , see please the code below.
i just declared how can i do that if i have a list and including it inside a list builder , then i can remove any widget on the screen by calling removeAt property
thanks in advance
child: Column(
children: <Widget>[BlocBuilder(
cubit: BlocProvider.of<AppBloc>(context),
builder: (BuildContext context, AppState state) {
if (state is AppUpdated && state.services.count > 0) {
return Expanded(
child: ListView.builder(
itemCount: state.services.count,
itemBuilder: (BuildContext context, int index) =>
Dismissible(
key: Key(state.service.toString()),
ListView.builder(
itemCount: state.services.count,
itemBuilder: (BuildContext context, int index) =>
Dismissible(
key: Key(state.service.toString()),
onDismissed: (direction) {
// Remove the item from the data source.
setState(() {
x.removeAt(index);
});
},
child: //your child here (maybe listivew)
),
),
I have kind of a form where I can add cards, each having 5 textfields and 2 switches. I would like to use a method to build the switch code (and the textfield code, but that is working). However, the switches refuse to show their intended state. I saw couple of similar questions. However, most were solved with a list view listing all switched/checkboxes next to one another (I have multiple cards with multiple textfields and multiple switches, each). This was close, but I don't really understand the answer (within the comments)
Actually some answers come up with the same (I guess more or less same because mine isn't working) code storing the switch state in a bool list. When debugging I can see that the values are correctly stored in the list. However, the changed value is not rendered upon state change.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class MainPage extends StatefulWidget {
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
var descrTECs = <TextEditingController>[];
var fixedSCs = [true]; //storing the switch values
var cards = <Card>[]; // storing the list of cards with forms
SizedBox createTextField(String placeholderStr, double fieldWidth) {
var tFieldController = TextEditingController();
switch (placeholderStr) { //switching placeholder to assign text controller to correct controller list
case "Description":
descrTECs.add(tFieldController);
break;
}
return SizedBox(width: fieldWidth, height: 25,
child: CupertinoTextField(
placeholder: placeholderStr,
controller: tFieldController,
),
);
}
SizedBox createSwitch(int pos) {
return SizedBox(width: 50, height: 25,
child: CupertinoSwitch(
value: fixedSCs[pos],
onChanged: (value) {
setState(() => fixedSCs[pos] = value); // value is stored in fixedSCs but not rendered upon rebuild
},
)
);
}
Card createCard() {
return Card(
child: Row(children: <Widget>[
Text('#p${cards.length + 1}:'),
Column(
children: <Widget>[
createSwitch(cards.length),
createTextField("Description", 70.0),
],),
],),
);
}
#override
void initState() {
super.initState();
cards.add(createCard()); // first card created upon start
}
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: SafeArea(
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder( // List Builder to show all cards
itemCount: cards.length,
itemBuilder: (BuildContext context, int index) {
return cards[index];
},
),
),
RaisedButton(
child: Text('add new'),
onPressed: () => setState(() {
fixedSCs.add(true); // bool element created to create next card
cards.add(createCard());} // create next card
),
),
],
),
),);
}
}
One thing I do not understand in general: Upon rebuild after a state change cards.length} should be my number of cards, let's say 3. And when it renders the 1st card, it passes the line Text("#p${cards.length + 1}"), so it should show #p3 and not #p1. What do I get wrong here?
I meanwhile got this working with quite some logic changes.
I put the switch builder into a stateless widget
class createSwitch extends StatelessWidget {
const createSwitch({
this.label, this.margin=const EdgeInsets.all(0.0), this.width, this.height, this.value, this.onChanged});
final String label; final EdgeInsets margin; final double width; final double height; final bool value;
final Function onChanged;
#override
Widget build(BuildContext context) {
return Container(
child: Row(
children: <Widget>[
Expanded(child: Text(label)),
CupertinoSwitch(
value: value,
onChanged: (bool newValue) {onChanged(newValue);},
),
],
),
),
} }
In the parent stateful controller I created a list to store the switches' state var parameterSCs = [true]; and each time I add a card I add a value whith clicking the button onPressed: () => setState(() {parameterSCs.add(true);}
I no longer store the cards widgets as a list. Instead, I build them directly in the code within a ListView.builder
ListView.builder(
itemCount: parameterSCs.length,
itemBuilder: (BuildContext context, int index) {
return Card( ...
In my real code I have 2 switches per card, so I always add 2 elements and the ListView count is then half of the parameterSCs' length.
I tried loads of approaches, this was the only one working
I have a hardcoded list that I want to map it to a list of widgets. The code below shows squiggly lines with the error The return type 'List<ItemWidget>' isn't a 'Widget', as defined by anonymous closure.dart(return_of_invalid_type_from_closure).
.................MISSING CODE....................
ListView.builder(
itemBuilder: (context, index) => items.map((item) => ItemWidget(item: item)).toList();
)
..................MISSING CODE....................
class ItemWidget extends StatelessWidget{
final Item item;
ItemWidget({this.item});
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Expanded(
child: FittedBox(
fit: BoxFit.fill,
child: Image.asset(item.iconPath)
)
),
Padding(
padding: const EdgeInsets.only(top: 15.0),
child: Text(item.name),
)
],
);
}
}
EDIT:
This is the list of items, currently I hold just an item for testing purposes.
List<Item> items = [
Item(name: 'Medicines', iconPath: '$ICON_BASE_PATH/medicines.svg'),
];
If you have any idea please let me know, thanks!
The issues is using the ListView.builder, the builder function expects you to return one Widget at a time corresponding to the index provided. Use ListView directly instead.
Example:
ListView(
children: items.map((item) => ItemWidget(item: item)).toList(),
);
Hope that helps!
If you want to use ListView.builder then you can use as following. This may helps you.
body: ListView.builder(
itemCount: items == null ? 0 : items.length,
itemBuilder: (BuildContext context, int index) {
return ItemWidget(
item: items[index],
);
},
),