When I'm trying to remove items from the listview using provider it removed last element from the list in flutter - flutter

When I'm trying to remove item(like 0 index item) from this listview using provider it removed the last item from the list. while I'm deleting last element from the list successfully remove last item. I'm bit confusing why this kind of problem is happening to me.
Here I'm posting some code please check give your valuable suggestion. Also demonstrate on this video what issue is happening
Link:https://drive.google.com/file/d/1UYl8Z7vEj_tZCaYzqe0VqZL2iMla5nIZ/view?usp=sharing
Expected result: Whenever user press delete button then delete that particular row(item).
Delete method:- This is the delete method It'll be call when user press delete button from the list.
Future<void> acceptdeclinerequest(String requestStatus,int requestId) async{
String token = await CustomPreferences.getpreferences('token');
Map<String, String> requestHeaders;
if (token.isNotEmpty) {
requestHeaders = {
'Accept': 'application/json',
'Authorization': 'Bearer ' + token
};
} else {
requestHeaders = {
'Accept': 'application/json',
};
}
var reqdata = {
"request_id":requestId.toString(),
"status":requestStatus
};
print('accept request data is $reqdata');
try
{
final response =
await http.post(Connection.url + 'respond-place-request', headers: requestHeaders,body: reqdata);
if (response.statusCode == 200) {
Map<String, dynamic> responseJson = json.decode(response.body);
final existingProductIndex = _items.indexWhere((prod) => prod.id == requestId);
var existingProduct = _items[existingProductIndex];
_items.removeAt(existingProductIndex);
notifyListeners();
return responseJson;
} /*else if (response.statusCode == 500) {
return servererrorresponse;
}*/
} catch (exception) {
throw exception;
}
}
Main Widget class: This is the main widget class where I define Listview widget. I've used provider to get data from api which is written in modal class to populate in Listview and Listview child widgets is in seprate class which is RequestWidgets. In this class I've passed rowitems data to show in listview.
GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
var connectionstatus;
var product;
var _isInit = true;
var _isLoading = false;
#override
void initState() {
super.initState();
}
#override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
if (_isInit) {
setState(() {
_isLoading = true;
});
Provider.of<BandRequestModal>(context).getBandRequestList().then((_) {
setState(() {
_isLoading = false;
});
});
}
_isInit = false;
super.didChangeDependencies();
}
#override
Widget build(BuildContext context) {
connectionstatus = Provider.of<ConnectivityResult>(context);
product = Provider.of<BandRequestModal>(context, listen: false);
// getRequestData();
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
key: _scaffoldKey,
appBar: CustomAppbar(
_scaffoldKey, Constants.requests, 100.0, filterRecord),
endDrawer: MenuDrawer(),
body:
/*(connectionstatus == ConnectivityResult.wifi ||
connectionstatus == ConnectivityResult.mobile)
? */
Consumer<BandRequestModal>(builder: (context, modal, child) {
return !_isLoading
? Container(child: LayoutBuilder(builder:
(BuildContext context, BoxConstraints constraints) {
return Container(
height: constraints.maxHeight,
child: modal.item.length > 0
? ListView.builder(
padding:
EdgeInsets.only(top: 10.0, bottom: 0.0),
itemCount: modal.item.length,
shrinkWrap: true,
// physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, int i) {
return RequestWidgets(data: modal.item[i]);
})
: Center(
child: new Text(
Constants.norecordfound,
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold),
),
),
// ],
// ),
);
}))
: Comman.loadingIndicator(Theme.of(context).primaryColor);
})
// : Comman.nointernetconnection(context)
// FutureBuilder<BandRequestModal>(
// future: Connection.bandRequestList(),
// builder: (context, snapshot) {
// switch (snapshot.connectionState)
// {
// case ConnectionState.none:
// break;
// case ConnectionState.waiting:
// return Comman.loadingIndicator(
// Theme.of(context).primaryColor);
// break;
// case ConnectionState.active:
// break;
// case ConnectionState.done:
// if (snapshot.hasError) {
// return Center(
// child: new Text(Constants.servererror),
// );
// }else if(snapshot.data==null){
// return Center(
// child: new Text(Constants.servererror),
// );
// } else if (snapshot.data.data.length == 0) {
// return Center(
// child: new Text(
// Constants.norecordfound,
// style: TextStyle(
// fontSize: 20.0, fontWeight: FontWeight.bold),
// ),
// );
// } else {
// return ListView.builder(
// padding:
// EdgeInsets.only(top: 10.0, bottom: 60.0),
// itemCount: snapshot.data.data.length,
// shrinkWrap: true,
// physics: NeverScrollableScrollPhysics(),
// itemBuilder: (context, int i) {
// return RequestWidgets(data:snapshot.data.data[i]);
// });
// }
// break;
// }
// }):Comman.nointernetconnection(context)
));
}
Child widget class: This is the row items class of listview In this class we used many widgets to show place data.
class _RequestWidgetsState extends State<RequestWidgets> {
var getData;
var product;
#override
void initState() {
// TODO: implement initState
getData = widget.data;
super.initState();
}
#override
Widget build(BuildContext context) {
product = Provider.of<BandRequestModal>(context, listen: false);
return Container(
// alignment: Alignment.topLeft,
margin: EdgeInsets.only(top: 5.0),
child: ListTile(
// contentPadding: EdgeInsets.zero,
key: ObjectKey(getData),
leading: CircleAvatar(
radius: 30,
backgroundColor: Colors.transparent,
child: ClipOval(
child: (getData.placeDetails.image != null &&
getData.placeDetails.image != '')
? Image.network(
getData.placeDetails.image,
width: 90,
height: 90,
fit: BoxFit.cover,
)
: Image.asset(
Res.defaultImage,
width: 90,
height: 90,
fit: BoxFit.cover,
)),
),
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: Text(getData.placeDetails.name,
style: TextStyle(
fontSize: 16.0,
fontFamily: 'Metropolis',
color: CustomColors.commentTitleColor))),
],
),
subtitle: Container(
margin: EdgeInsets.only(top: 1.0),
child: Column(children: <Widget>[
Container(
margin: EdgeInsets.only(top: 1.0),
child: Row(children: <Widget>[
Expanded(
child: Text(getData.placeDetails.address,
style: TextStyle(
fontSize: 15.0,
height: 1.2,
fontFamily: 'Metropolis',
color: CustomColors.commentSubtitleColor))),
]),
),
Container(
margin: EdgeInsets.only(top: 15.0, bottom: 15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[],
)),
Divider(
color: CustomColors.commentlineColor,
thickness: 0.8,
)
])),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
GestureDetector(
child: CircleAvatar(
radius: 20,
backgroundColor: Colors.green,
child: Icon(
Icons.check,
color: Colors.white,
),
),
onTap: () {
acceptrejectpopup('1');
// {
// print('accept data $data');
// Comman.hideLoading(context);
// Comman.showSnakBar(data['message'],context);
// });
},
),
SizedBox(
width: 15.0,
),
GestureDetector(
child: CircleAvatar(
backgroundColor: Colors.red,
child: Icon(
Icons.clear,
color: Colors.white,
),
),
onTap: () {
// Comman.showLoading(context);
acceptrejectpopup('0');
/*product.acceptdeclinerequest('0',getData.id.toString()).then((data){
print('decline data $data');
Comman.hideLoading(context);
Comman.showSnakBar(data['message'],context);
});*/
},
)
],
),
),
);
}
//accept and reject
void acceptRejectRequest(String requestStatus) async {
try {
var response =
await product.acceptdeclinerequest(requestStatus, getData.id);
if (response['status'] == Constants.status_true) {
Comman.hideLoading(context);
Comman.showSnakBar(response['message'], context);
// setState(() {});
} else {
Comman.hideLoading(context);
}
} catch (exception) {
Comman.hideLoading(context);
Comman.showSnakBar(Constants.servererror, context);
}
}
//request accept/reject popup
Future<void> acceptrejectpopup(String reqStatus) {
return showDialog(
context: context,
builder: (context) => new AlertDialog(
title: new Text('Alert!',
style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold)),
content: new Text(reqStatus == '1'
? Constants.reqAcceptmessage
: Constants.reqRejectemessage),
actions: <Widget>[
new FlatButton(
onPressed: () => Navigator.of(context).pop(),
child: new Text(Constants.notxt),
),
new FlatButton(
onPressed: () {
Navigator.of(context).pop();
Comman.showLoading(context);
acceptRejectRequest(reqStatus);
},
child: new Text(Constants.yestxt),
),
],
),
);
}

The provider is working just fine, the problem is when the provider notify the consumer the ListView updates the children, but the StatefulWidget check they're the same type (They're all RequestWidget) so they just update themselves (if you don't provide a key to the StatefulWidget they will try to check if they're the same element and update via the didChangeDependencies method), but you're updating the getData var in initState (which will call only once) so even if the consumer updates the value won't. Try it like this
#override
void initState() {
// TODO: implement initState
//getData = widget.data; not here
super.initState();
}
#override
void didChangeDependencies() {
// TODO: implement initState
getData = widget.data; //update it here
super.didChangeDependencies();
}
Other option would be just to give a specific key when building your widget in the itemBuilder so when the consumer updates it changes them accordingly
return RequestWidgets(key: ValueKey(modal.item[i].id),data: modal.item[i]);
// Or some value unique for each item

The problem here I guess is, in your Child widget class, since I can't see any requestId of the selected card being passed to the acceptdeclinerequest().
Your acceptdeclinerequest() expects two unique arguments to be passed when called:
String requestStatus
int requestId
If you look closely into the Child widget class, you are just passing requestStatus. I wonder from where are you getting this getData.id, and how is it identifying that some particular card is selected.
// look here, only requestStatus is being passed
onTap: () {
acceptrejectpopup('0');
}
// and here
onTap: () {
acceptrejectpopup('1');
}
And in your acceptRejectRequest, you are only passing requestStatus
acceptRejectRequest(reqStatus);
And then you call your acceptdeclinerequest() with this data
// machine is confused, where are we getting the getData.id
// it assumes the id as per it's need, hence the error
await product.acceptdeclinerequest(requestStatus, getData.id);
The machine is trying to figure out, which element you selected. Try to give the id from the selected card, and pass it to the method with correct getData.id of that particular element.
Suggestion: Pass in your id of the selected card when you are tapping on it, and then call your methods, and then pass it along to get the right requestId and remove it. Let your methods acceptrejectpopup() and acceptRejectRequest() accept the id of the selected item and then finally pass it to your acceptdeclinerequest()
// first step
onTap: () => acceptrejectpopup('0', your_card_reuqest_id);
// second step, pass data from the above popup method to acceptRejectRequest()
acceptRejectRequest(reqStatus, requestId);
//finally from acceptRejectRequest(reqStatus, requestId), pass it to the final method acceptdeclinerequest
acceptdeclinerequest(requestStatus, requestId);

Related

Refresh indicator doesn't update data post after caching in Flutter

I am facing an issue when I pull to refresh, I need that after pull to refresh gesture new articles available will be visible in the news page, but this doesn't happen.
I created the cache system, but once I pull to refresh new data, the news page doesn't load new articles.
What can I do to solve this issue?
News page
class _NewsPageState extends State<NewsPage> {
/// News service
final ApiNewsPage categoryNews = ApiNewsPage();
late bool isLoading;
/// Start Refresh indicator upload new articles function
final NewArticlesPage updateArticles = NewArticlesPage();
ScrollController scrollController = ScrollController();
//final List<ArticleModel> _posts = [];
//
#override
void initState() {
super.initState();
refreshArticles();
}
/// Call this when the user pull down the screen
Future<void> refreshArticles() async {
Future.delayed(const Duration(seconds: 2), () {
setState(() {
updateArticles.updateArticles();
print("Uploading new articles");
//_posts.add();
});
return updateArticles.updateArticles();
});
}
/// End Refresh indicator upload new articles function
///
///
#override
Widget build(BuildContext context) {
return RefreshIndicator(
displacement: 0,
color: assofacileMainColor,
backgroundColor: Colors.white,
onRefresh: refreshArticles,
child: Container(
child: FutureBuilder<List?>(
future: categoryNews.getNewsArticles(),
builder: (context, snapshot) { // AsyncSnapshot
if (snapshot.hasData) {
if (snapshot.data?.length == 0) {
return const NoArticle();
}
return ListView.builder(
controller: scrollController,
itemCount: snapshot.data?.length++,
physics: const AlwaysScrollableScrollPhysics(),
itemBuilder: (context, i) {
return Card(
margin: const EdgeInsets.all(8),
elevation: 5,
shadowColor: Colors.black26,
color: Colors.white,
child: InkWell(
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: 190,
width: double.infinity,
child:
Image(
image: AdvancedNetworkImage(
snapshot.data![i]["_embedded"]['wp:featuredmedia'][0]["media_details"]["sizes"]["medium"]["source_url"],
useDiskCache: true,
cacheRule: const CacheRule(maxAge: Duration(days: 1)),
),
fit: BoxFit.cover,
),
// CachedNetworkImage(
// cacheManager: CacheManager(
// Config(snapshot.data![i]["_embedded"]['wp:featuredmedia'][0]["media_details"]["sizes"]["medium"]["source_url"],
// stalePeriod: const Duration(days: 1),
// )
// ),
// //cacheManager: DioCacheManager.instance,
// imageUrl: snapshot.data![i]["_embedded"]['wp:featuredmedia'][0]["media_details"]["sizes"]["medium"]["source_url"],
// // checkIfUrlContainsPrefixHttps(
// // _post != null
// // ? _post[0].urlImageSource
// // : "https:" + snapshot.data![i]["_embedded"]['wp:featuredmedia'][0]["media_details"]["sizes"]["thumbnail"]["source_url"],
// // ),
// //snapshot.data![i]["_embedded"]["wp:featuredmedia"][0]["link"],
// //"https:" + snapshot.data![i]["_embedded"]['wp:featuredmedia'][0]["media_details"]["sizes"]["medium"]["source_url"],
// fit: BoxFit.cover,
// placeholder: (context, url) => Image.asset("assets/gif/shimmer.gif",
// width: double.infinity,
// height: 190,
// fit: BoxFit.cover,
// ),
// errorWidget: (context, url, error) => Image.asset("assets/images/unloadedImage.png",
// width: 250, height: 250),
// ),
),
// Title article
Column(
children: [
Padding(
padding: const EdgeInsets.only(left:16, top: 16, bottom: 16),
child: Row(
children: [
Expanded(
child: Text(
snapshot.data![i]["title"]["rendered"]
.replaceAll("’", "'")
.replaceAll("<p>", "")
.replaceAll("</p>", ""),
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
fontFamily: "Raleway",
),
overflow: TextOverflow.ellipsis,
maxLines: 2,
//softWrap: false,
),
),
],
),
)
],
),
],
),
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ArticlePage(data: snapshot.data?[i]),
),
);
},
),
);
},
);
} else if (snapshot.hasError) {
return const NoInternet();
} else {
/// Shimmer
return ShimmerEffect();
}
}
),
),
);
}
}
Fetch and create cache
class ApiNewsPage {
final String url = newsJsonLink;
Future<List?> getNewsArticles() async {
String nameDB = "articledata.json";
var dir = await getTemporaryDirectory();
File file = File(dir.path + "/" + nameDB);
if(file.existsSync()) {
print("Loading Articles from cache");
var jsonDB = file.readAsStringSync();
List response = json.decode(jsonDB);
return response;
} else {
var response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
//await File(nameDB).exists();
var jsonResponse = response.body;
List newArticles = json.decode(jsonResponse);
//File(nameDB).deleteSync(recursive: true);
/// save json in local file
file.writeAsStringSync(jsonResponse, flush: true, mode: FileMode.write);
print("Fetching new articles from internet");
return newArticles;
}
}
}
}
// Create new db
class NewArticlesPage {
final String url = newsJsonLink;
Future<List?> updateArticles() async {
try {
var response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
print("Fetching new articles from internet");
return jsonDecode(response.body);
} else {
return Future.error("Impossibile ricevere i dati, prova a controllare la connessione");
}// ignore: non_constant_identifier_names
} catch (SocketException) {
return Future.error("Impossibile caricare gli articoli");
}
}
}

Recommended books list display based on a string constant returns exception

I need to show recommended books based on a string constant 'Recommended', but when I call, the method it returns
EXCEPTION CAUGHT BY IMAGE RESOURCE SERVICE
The following ImageCodecException was thrown resolving an image codec:
Failed to load network image.
Image URL:
Where image is getting fine from firebase along with all other fields. Below is the getrecommendedbooks method that
I do display fields onto the Page. PLEASE HELP.
THANK YOU.
Here is the code:
getSpecifiedBooks(String title) {
// debugPrint("requested book is $title");
if (title == Constants.recommendedConst) {
debugPrint("recommended requested");
return recommendedBooksList;
} else if (title == Constants.latestByMatabConst) {
return latestBooksList;
} else if (title == Constants.onSaleConst) {
return onSaleList;
} else if (title == Constants.favoritesConst) {
return favoriteBookList;
} else if (title == Constants.allItemsConst) {
return bookList;
} else if (title == Constants.searchConst) {
return bookList;
} else {
return [];
}
}
class BookController extends GetxController {
final recommendedBooksList = [].obs;
void onInit() {
fetchBooks();
super.onInit();
}
void fetchBooks() async {
try {
isLoading(true);
var books = await databaseService.getBooks();
// var favoriteBookIDs = await databaseService.getFavoriteBookIDs();
RxList<dynamic> recommendedBooks =
await databaseService.getRecommendedBooks();
RxList<dynamic> latestBooks = await databaseService.getLatestBooks();
RxList<dynamic> onSaleBooks = await databaseService.getOnSaleBooks();
bookList.assignAll(books);
// await getFavoriteBooks(favoriteBookIDs);
recommendedBooksList.assignAll(recommendedBooks);
latestBooksList.assignAll(onSaleBooks);
// latestBooksList.assignAll(latestBooks); //TODO uncomment this line and comment one above it when books data is updated in firebase with createdAt field in books
onSaleList.assignAll(books);
debugPrint("fetched books");
} finally {
isLoading(false);
}
}
Future<RxList> getRecommendedBooks() async {
RxList books = [].obs;
RxInt itemCount = 1.obs;
Query<Map<String, dynamic>> booksQuery = FirebaseFirestore.instance
.collection("books")
.where("isRecommended", isEqualTo: true);
await booksQuery.get().then(
(value) {
for (var doc in value.docs) {
Book bookItem = Book(
author: doc['author'],
title: doc['title'],
price: doc['price'].toDouble(),
coverImage: doc['coverImage'],
bookID: doc.id,
rating: doc['ratings'].toDouble(),
description: doc['description'],
discountPercentage: doc['discountPercentage'],
isLiked: false,
itemCount: itemCount,
);
books.add(bookItem);
}
},
);
return books;
}
Display Recommended Widget:
#override
Widget build(BuildContext context) {
return OutlinedButton(
child: const Text(' Show Recommended Books',
style: TextStyle(color: Colors.white)),
onPressed: () {
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => HomePageScreen()),
// );
// Navigator.pop(context);
Get.off(VerticalGrid(verticalGridTitle: Constants.recommendedConst));
},
);
}
}
Image Widget Render:
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.fromLTRB(20.0, 20, 20, 20),
child: Column(children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
widget.verticalGridTitle,
style: TextStyle(
color: secondaryColor,
fontSize: 20,
fontWeight: FontWeight.bold),
),
GestureDetector(
onTap: () {
Get.to(() => BookMagazineTapbar(
titleText: widget.verticalGridTitle,
));
},
child: Row(
children: [
Text(
"seeAll".tr,
style: TextStyle(
color: mainColor,
fontSize: 20,
fontWeight: FontWeight.bold),
),
Icon(Icons.arrow_forward, color: mainColor)
],
),
)
],
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 30, 20, 20),
child: Container(
color: Colors.white,
child: GridView.count(
crossAxisCount: 2,
crossAxisSpacing: 2.0,
mainAxisSpacing: 2.0,
shrinkWrap: true,
scrollDirection: Axis.vertical,
physics: const NeverScrollableScrollPhysics(),
children: List.generate(bookList.length, (index) {
return Padding(
padding: const EdgeInsets.only(bottom: 18.0),
child: GestureDetector(
onTap: () {
if (cartBookController.isInTheCart(index)) {
} else {}
Get.to(BookDetailsPage(
type: Constants.bookConst,
index: index,
cartButtonText: 'Add to Cart',
));
},
child: MyNetworkImage(
imageUrl: bookList[index].coverImage,
),
),
);
}),
)),
)
])),
);
}

Flutter Cupertino Picker errors out on first item if picker isn't scrolled

The app I'm building uses a Cupertino Picker that shows a list of items to select, in this case the names of the US States. The first item defaults to the first item in the list ('ak'), when the button to select the item is pressed, the app errors out. This only happens with the first item, when the picker isn't scrolled. If the picker is scrolled and the user goes back to the first item, it works fine.
class StateSelectScreen extends StatefulWidget {
static const String id = 'state_select_screen';
#override
_StateSelectScreenState createState() => _StateSelectScreenState();
}
class _StateSelectScreenState extends State<StateSelectScreen> {
String selectedState = 'ak';
bool showSpinner = false;
DropdownButton<String> androidDropdown() {
List<DropdownMenuItem<String>> dropdownItems = [];
for (String state in statesList) {
var newItem = DropdownMenuItem(
child: Text(
USStates.getName(state).toUpperCase(),
textAlign: TextAlign.center,
),
value: state,
);
dropdownItems.add(newItem);
}
return DropdownButton<String>(
dropdownColor: Colors.black26,
autofocus: true,
focusColor: Colors.black26,
style: TextStyle(
fontSize: k30PointFont,
),
value: selectedState,
items: dropdownItems,
onChanged: (value) {
setState(() {
selectedState = value;
getStateData();
});
},
);
}
CupertinoPicker iOSPicker() {
List<Text> pickerItems = [];
for (String state in statesList) {
pickerItems.add(Text(USStates.getName(state.toUpperCase())));
}
return CupertinoPicker(
backgroundColor: kCupertinoPickerBackgroundColor,
itemExtent: kCupertinoPickerItemExtent,
onSelectedItemChanged: (selectedIndex) {
setState(() {
selectedState = USStates.getName(statesList[selectedIndex]);
getStateData();
});
},
children: pickerItems,
);
}
Map<String, dynamic> selectedStateData = {};
bool isWaiting = false;
void getStateData() async {
isWaiting = true;
try {
var stateData = await GetData().getStateData(selectedState);
isWaiting = false;
setState(() {
selectedStateData = stateData;
});
} catch (e) {
print(e);
}
}
#override
void initState() {
super.initState();
getStateData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(kAppBarTitle),
),
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Flexible(
child: Padding(
padding: EdgeInsets.only(top: kStateSelectScreenFlexEdgeInsetsTop, bottom: kStateSelectScreenFlexEdgeBottom),
child: Hero(
tag: kHeroTag,
child: Container(
height: 200.0,
child: Image.asset(kHeroImageAsset),
),
),
),
),
Container(
child: Column(
children: <Widget>[
Container(
height: kStateSelectScreenContainerHeight,
alignment: Alignment.center,
padding: EdgeInsets.only(bottom: kStateSelectScreenContainerPaddingBottom),
child: Platform.isIOS ? iOSPicker() : androidDropdown(),
),
BottomButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return ResultsScreen(
covidData: selectedStateData,
location: selectedState,
);
},
),
);
},
buttonTitle: kCheckStateResultsButtonTitle,
),
SizedBox(
height: kHeight15,
),
BottomButton(
onPressed: () {
Navigator.pushNamed(context, MenuScreen.id);
},
buttonTitle: kMainMenuButtonTitle,
),
],
),
),
],
),
),
);
}
}
I have recreated your problem, but don't see any error.
https://codepen.io/flakerimi/pen/poRywLZ
You said when the button to select the item is pressed, the app errors out.
Which button ? I don't see any
I have added scrollController: FixedExtentScrollController(initialItem: 1), but I don't think thats the case.
return CupertinoPicker(
scrollController: FixedExtentScrollController(initialItem: 1),
backgroundColor: Colors.white,
itemExtent: 30,
onSelectedItemChanged: (selectedIndex) {
setState(() {
selectedState = statesList[selectedIndex];
print(selectedState);
});
},
children: pickerItems,
);

Flutter Tried calling: [] error on list builder

I am showing list-builder i need to show just a static data right now I am just check itemCount right now later'll show data but it's showing error .
Here is my code
class _OrderPageState extends State<OrderPage> {
bool showCards = false;
var data;
#override
void initState() {
this.getOrders();
}
getOrders() async{
final storage = new FlutterSecureStorage();
String userId = await storage.read(key: "_userID");
String url =
'http://retailapi.airtechsolutions.pk/api/orders/customer/${userId}/0';
print(url);
http.Response res = await http.get(
url,
);
var data = json.decode(res.body.toString());
print(data);
if(data['description'].toString() == "Success"){
print(data['Orders']);
print(data['Orders'].length); //its printing 6 here
setState(() {
showCards = true;
});}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Order', style: Theme.of(context).textTheme.headline4),
),
body: showCards ? Container(
child: ListView.builder(
itemCount: data['Orders'].length,
shrinkWrap: true,
padding: EdgeInsets.symmetric(horizontal: 18.0, vertical: 20.0),
itemBuilder: (context, index) {
var order = orderList[index];
return SideInAnimation(index, child:GestureDetector(
onTap: () {
// Get.to(OrderDetailPage(order: order));
},
child: Container(
width: double.infinity,
padding: EdgeInsets.all(12.0),
margin: EdgeInsets.only(bottom: 15.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15.0),
border: Border.all(color: Theme.of(context).accentColor),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(order.id,
style: Theme.of(context)
.textTheme
.headline3
.copyWith(color: Theme.of(context).primaryColor)),
SizedBox(height: 12.0),
Text(order.dateOrder, style: Theme.of(context).textTheme.subtitle2),
Divider(),
orderCardItem(context,
title: "order.orderstatus", data: order.orderStatus),
SizedBox(height: 12.0),
orderCardItem(context,
title: "order.items",
data: "${order.totalItem} " + tr("order.itemspurchased")),
SizedBox(height: 12.0),
priceItem(context,
title: "order.price", data: "\$ ${order.totalPrice}"),
],
),
),
));
},
),
) : Container(),
);
}
}
In my function its printing the length by in List builder its showing an error that Tried calling: ` But on the print where API load it's showing the length 6.
First you need to initalize a list or array then simply add your data into that variable and then call this variable to your listview builder
var ordersData = [];
then your getData() method should be like this
getOrders() async {
...
if (data['description'].toString() == "Success") {
ordersData.add(data['Orders']); // Add your data to array or list
print(ordersData.length); //its printing 6 here
}
...
}
Here your Listview like this
ListView.builder(
itemCount: ordersData.length, // Here you need to pass this lenght
...
)

Need to Hot Reload flutter app every time in order to fetch data from Firebase realtime database

Here is my code:
class CategoryHomeScreen extends StatefulWidget {
#override
_CategoryHomeScreenState createState() => _CategoryHomeScreenState();
}
class _CategoryHomeScreenState extends State<CategoryHomeScreen> {
List<CategoriesOnly> categoriesOnlyList =[];
List<CategoryItems> categoryItemList = [];
#override
void initState() {
// TODO: implement initState
getCategoriesName();
super.initState();
}
Future<void> getCategoriesName() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var userPin = prefs.getString('pin');
var CategoryName = FirebaseDatabase.instance.reference().child('CategoryNames').child(userPin).once()
.then((DataSnapshot dataSnapshot){
var key = dataSnapshot.value.keys;
for(var i in key)
{
// print(dataSnapshot.value[i]['Name']);
CategoriesOnly categoriesOnly = new CategoriesOnly(
dataSnapshot.value[i]['Name']
);
categoriesOnlyList.add(categoriesOnly);
}
});
var categoryItemDetails = FirebaseDatabase.instance.reference().child('Categories').child(userPin).once()
.then((DataSnapshot dataSnapshot){
var key = dataSnapshot.value.keys;
for(var i in key)
{
CategoryItems categoryItems = new CategoryItems(
dataSnapshot.value[i]['CategoryName'],
dataSnapshot.value[i]['MarketPrice'],
dataSnapshot.value[i]['Name'],
dataSnapshot.value[i]['OurPrice'],
dataSnapshot.value[i]['TotalDiscount'],
dataSnapshot.value[i]['Weight']
);
categoryItemList.add(categoryItems);
}
});
}
#override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: Colors.black, //or set color with: Color(0xFF0000FF)
));
return Scaffold(
backgroundColor: Colors.black,
body: SafeArea(
child:
ListView.builder(
itemCount: categoriesOnlyList.length,
itemBuilder: (context, index1) =>
Column(children: [
Text(categoriesOnlyList[index1].Name,style: TextStyle(color:Colors.white),),
Container(
height: 200,
decoration: BoxDecoration(borderRadius: BorderRadius.circular(8)),
child:
ListView.builder(itemCount: categoryItemList.length,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return categoriesOnlyList[index1].Name == categoryItemList[index].CategoryName?
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 200,
width: 200,
decoration: BoxDecoration(borderRadius: BorderRadius.circular(8)),
child: Card(
color: Colors.white,
child: Text(categoryItemList[index]
.Name,style: TextStyle(),overflow: TextOverflow.ellipsis,)),
),
):Container(
);
}),
),
]),
)
),
);
}
}
This is my app where I'm loading data from firebase realtime database. When I install the app it doesn't show any data but when I reload(hot reload) the app it shows all the data and when I quit the app and again launch it I'm not able to see the data again. But I want my page to show some loading widget until it loads the data and then return the page. Or simple the page with data.
Likely because categoryItemList.length is 0.
you can check this using the debugger or display something when the length is 0.
class CategoryHomeScreen extends StatefulWidget {
#override
_CategoryHomeScreenState createState() => _CategoryHomeScreenState();
}
class _CategoryHomeScreenState extends State<CategoryHomeScreen> {
List<CategoriesOnly> categoriesOnlyList = [];
List<CategoryItems> categoryItemList = [];
#override
void initState() {
// TODO: implement initState
getCategoriesName();
super.initState();
}
Future<void> getCategoriesName() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var userPin = prefs.getString('pin');
var CategoryName = FirebaseDatabase.instance
.reference()
.child('CategoryNames')
.child(userPin)
.once()
.then((DataSnapshot dataSnapshot) {
var key = dataSnapshot.value.keys;
for (var i in key) {
// print(dataSnapshot.value[i]['Name']);
CategoriesOnly categoriesOnly =
new CategoriesOnly(dataSnapshot.value[i]['Name']);
categoriesOnlyList.add(categoriesOnly);
}
});
var categoryItemDetails = FirebaseDatabase.instance
.reference()
.child('Categories')
.child(userPin)
.once()
.then((DataSnapshot dataSnapshot) {
var key = dataSnapshot.value.keys;
for (var i in key) {
CategoryItems categoryItems = new CategoryItems(
dataSnapshot.value[i]['CategoryName'],
dataSnapshot.value[i]['MarketPrice'],
dataSnapshot.value[i]['Name'],
dataSnapshot.value[i]['OurPrice'],
dataSnapshot.value[i]['TotalDiscount'],
dataSnapshot.value[i]['Weight']);
categoryItemList.add(categoryItems);
}
});
}
#override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarColor: Colors.black, //or set color with: Color(0xFF0000FF)
),
);
return Scaffold(
backgroundColor: Colors.black,
body: SafeArea(
child: ListView.builder(
itemCount: categoriesOnlyList.length, // place breakpoint here
itemBuilder: (context, index1) {
if (categoriesOnlyList == null || categoriesOnlyList.length == 0) {
return CircularProgressIndicator(); // you should see loading animation if list is empty
}
return Column(
children: [
Text(
categoriesOnlyList[index1].Name,
style: TextStyle(color: Colors.white),
),
Container(
height: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
),
child: ListView.builder(
itemCount: categoryItemList.length, // place breakpoint here
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
if (categoryItemList == null || categoryItemList.length == 0) {
return CircularProgressIndicator(); // you should see loading animation if list is empty
}
return categoriesOnlyList[index1].Name ==
categoryItemList[index].CategoryName
? Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 200,
width: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8)),
child: Card(
color: Colors.white,
child: Text(
categoryItemList[index].Name,
style: TextStyle(),
overflow: TextOverflow.ellipsis,
),
),
),
)
: Container();
},
),
),
],
),
}
),
),
);
}
}
The solution would be to use a FutureBuilder
Word of warning: The application will run the build method multiple times, it's good practice to place anything you don't want to be repeatedly called (like database calls or changing system overlays) outside of the method.
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarColor: Colors.black, // or set color with: Color(0xFF0000FF)
),
);