How can I automatically add widgets to the body of my scaffold? - flutter

I'm trying to have the body of my scaffold return list Tiles that are built automatically, much like posts on a social media app. However, it only returns and empty container, with only its background colour.
Widget _buildListingWidgets(List<Widget> listing) {
return ListView.builder(
itemBuilder: (BuildContext context, int index) => listing[index],
itemCount: listing.length,
);
}
#override
Widget build(BuildContext context) {
final listing = <Listing>[];
for (var i = 0; i < _listingNames.length; i++) {
listing.add(Listing(
describe: _describe[i],
building: _building[i],
location: _location[i],
availability: _availability[i],
));
}
final listView = Container(
color: Colors.black,
padding: EdgeInsets.symmetric(horizontal: 8.0),
child: _buildListingWidgets(listing),
);
...
return Scaffold(
appBar: appBar,
body: listView,
...
);

Keep you code as it now, and modify the ListViewBuilder to look like this:
Widget _buildListingWidgets(List<Widget> listing) {
return ListView.builder(
itemCount: listing.length,
itemBuilder: (BuildContext context, int index) {
return Container(child:
Text(listing[index].describe),
);
}
);
}
It should work.

You seem to have overly complicated how to build your ListView, without using it's inherent functionality. You can do it this way:
class Issue66841743 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.black,
padding: EdgeInsets.symmetric(horizontal: 8.0),
child: MyList(listingNames: listing,),
);
}
}
class MyList extends StatelessWidget {
final List listingNames;
const MyList({Key key, this.listingNames}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: listingNames.length,
itemBuilder: (context, index) {
return Listing(
describe: _describe[i],
building: _building[i],
location: _location[i],
availability: _availability[i],
);
}
);
}
}
Have in mind that you did not provide us with the other Lists, _describe, _building, _location and _availability. These also signal me that there are further issues in your code. As you very well could have a class with all the properties pertaining to a certain listing.

Related

Bad state: field does not exist within the DocumentSnapshotPlatform -flutter

So, all I'm trying to do is create a StreamBuilder that listens to the "raids" collection on Firebase, and return a widget for each document using a ListView.builder (though I'm not entirely sure this is the right way to go about this, I'm pretty new).
From everything I've seen, my code should be working properly but obviously I've misunderstood something along the way.
I've already confirmed that the field I'm trying to pass into my Text widget is accurate and that there is data within the snapshots, what do I do next?
class HostedRaids extends StatefulWidget {
const HostedRaids({Key? key}) : super(key: key);
#override
State<HostedRaids> createState() => _HostedRaidsState();
}
class _HostedRaidsState extends State<HostedRaids> {
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: (FirebaseFirestore.instance.collection('raids').snapshots()),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.docs.length,
itemBuilder: (BuildContext context, int index) {
var raidSnapshot = snapshot.data!.docs[index];
return Row(
children: [
Text(
raidSnapshot['creatorID'],
style: const TextStyle(color: Colors.white),
),
],
);
},
);
} else {
throw ('error');
}
});
}
}

Saving the data to a dynamic list on another screen based on previous selection in flutter

Am a completely new flutter dev. I am trying to save a document from a queried firestore list on another saved documents page like an add to cart functionality. Am passing doc id as arguments to another page from firestore so that I get data based on the previous selection. Now how can I send the firestore reference and save it to the other screen without navigating to it so that users are able to save their favorite docs on another page and access them? Here is my Assignment page that lists the docs based on the previous selection.
class Assignments extends StatelessWidget {
final String programId;
final String yearId;
final String semesterId;
final String courseId;
const Assignments(
{Key key, this.programId, this.yearId, this.semesterId,
this.courseId})
: super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar2(title: 'Assigment'.toUpperCase(), ),
body: Column(
children: [
Expanded(
child: ContentArea(
addPadding: false,
child: StreamBuilder(
stream:
getAssignment(programId, yearId, semesterId, courseId),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(
color: kOnSurfaceTextColorYellow),
);
}
return ListView.separated(
padding: UIParameters.screenPadding,
shrinkWrap: true,
itemCount: snapshot.data.docs.length,
itemBuilder: (BuildContext context, int index) {
final data = snapshot.data.docs[index];
return DisplayCard(
title: data['nameOfAssignment'],
icon: Icons.add,
// Here is the action i want that should save the documment to
// the SavedPage empty list without navigating to it
onTapIconSave: (){}
onTap: () => Get.to(Pdf(
nameOfAssignment: data['nameOfAssignment'],
pdfUrl: data['pdfUrl'],
)),
);
},
separatorBuilder: (BuildContext context, int index) {
return const SizedBox(
height: 10,
);
},
);
})),
),
],
),
);
}
}
Here is the SavedPage which may be similar to the cart page. Am not sure what to do in order to save the Document from the Assignment Page in a Dynamic growable list
class Saved extends StatefulWidget {
const Saved({ Key key }) : super(key: key);
#override
State<Saved> createState() => _SavedState();
}
class _SavedState extends State<Saved> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: const CustomAppBar2(title: 'Saved'),
body: Column(
children: [],
),
);
}
}
You can add a state management package like Provider or Bloc, also you could save your data in your local database and access them from there. I recommend Provider, easy to use, and its what you need.

The expression doesn't evaluate to function, so it can't be invoked?

class ShoppingListState extends State<ShoppingList> {
#override
Widget build(BuildContext context) {
final List<String> shoppingItems = new List();
shoppingItems.add("pain");
shoppingItems.add("tomate");
return ListView.builder(
padding: const EdgeInsets.all(16.0),
itemCount: shoppingItems.length,
itemBuilder: (context,i) {
return Text(shoppingItems(i));
}
);
}
}
The error is on return Text(shoppingItems());
shoppingItems is not a function but a List, you might want to access the element at the i position so you replace your code using shoppingItems[i].

Flutter/Dart - Get index number of PageView.Builder for use in a Text Widget?

I've got a PageView.builder within a StatelessWidget. I need to get the current index number of the currently viewed page to appear in a text widget in my build.
Was hoping I could simply use currentIndex.toString() as a variable in the text widget but Android Studio underlines it in red and warns me of undefined name currentIndex. How can I get the correct variable?
class StageBuilder extends StatelessWidget {
final List<SpeakContent> speakcrafts;
StageBuilder(this.speakcrafts);
final PageController controller = PageController(initialPage: 0);
#override
Widget build(context) {
return PageView.builder(
controller: controller,
itemCount: speakcrafts.length,
itemBuilder: (context, int currentIndex) {
return createViewItem(speakcrafts[currentIndex], context);
},
);
}
Widget createViewItem(SpeakContent speakcraft, BuildContext context) {
return Container(
child: Text(currentIndex.toString()),
)
}
}
You need to pass the currentIndex into your createViewItem
class StageBuilder extends StatelessWidget {
final List<SpeakContent> speakcrafts;
StageBuilder(this.speakcrafts);
final PageController controller = PageController(initialPage: 0);
#override
Widget build(context) {
return PageView.builder(
controller: controller,
itemCount: speakcrafts.length,
itemBuilder: (context, int currentIndex) {
return createViewItem(speakcrafts[currentIndex], context, currentIndex);
},
);
}
Widget createViewItem(SpeakContent speakcraft, BuildContext context, int currentIndex) {
return Container(
child: Text(currentIndex.toString()),
);
}
}

How to properly initialize a Future in Flutter Provider

so I am trying to build up a list in my provider from a Future Call.
So far, I have the following ChangeNotifier class below:
class MainProvider extends ChangeNotifier {
List<dynamic> _list = <dynamic>[];
List<dynamic> get list => _list;
int count = 0;
MainProvider() {
initList();
}
initList() async {
var db = new DatabaseHelper();
addToList(Consumer<MainProvider>(
builder: (_, provider, __) => Text(provider.count.toString())));
await db.readFromDatabase(1).then((result) {
result.forEach((item) {
ModeItem _modelItem= ModeItem.map(item);
addToList(_modelItem);
});
});
}
addToList(Object object) {
_list.add(object);
notifyListeners();
}
addCount() {
count += 1;
notifyListeners();
}
}
However, this is what happens whenever I use the list value:
I can confirm that my initList function is executing properly
The initial content from the list value that is available is the
Text() widget that I firstly inserted through the addToList function, meaning it appears that there is only one item in the list at this point
When I perform Hot Reload, the rest of the contents of the list seems to appear now
Notes:
I use the value of list in a AnimatedList widget, so I am
supposed to show the contents of list
What appears initially is that the content of my list value is only one item
My list value doesn't seem to automatically update during the
execution of my Future call
However, when I try to call the addCount function, it normally
updates the value of count without needing to perform Hot Reload -
this one seems to function properly
It appears that the Future call is not properly updating the
contents of my list value
My actual concern is that on initial loading, my list value doesn't
properly initialize all it's values as intended
Hoping you guys can help me on this one. Thank you.
UPDATE: Below shows how I use the ChangeNotifierClass above
class ParentProvider extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<MainProvider>(
create: (context) => MainProvider(),
),
],
child: ParentWidget(),
);
}
}
class ParentWidget extends StatelessWidget {
final GlobalKey<AnimatedListState> listKey = GlobalKey<AnimatedListState>();
#override
Widget build(BuildContext context) {
var mainProvider = Provider.of<MainProvider>(context);
buildItem(BuildContext context, int index, Animation animation) {
print('buildItem');
var _object = mainProvider.list[index];
var _widget;
if (_object is Widget) {
_widget = _object;
} else if (_object is ModelItem) {
_widget = Text(_object.unitNumber.toString());
}
return SizeTransition(
key: ValueKey<int>(index),
axis: Axis.vertical,
sizeFactor: animation,
child: InkWell(
onTap: () {
listKey.currentState.removeItem(index,
(context, animation) => buildItem(context, index, animation),
duration: const Duration(milliseconds: 300));
mainProvider.list.removeAt(index);
mainProvider.addCount();
},
child: Card(
child: Padding(
padding: const EdgeInsets.all(32.0),
child: _widget,
),
),
),
);
}
return Scaffold(
appBar: AppBar(),
body: Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(32.0),
child: mainProvider.list == null
? Container()
: AnimatedList(
key: listKey,
initialItemCount: mainProvider.list.length,
itemBuilder:
(BuildContext context, int index, Animation animation) =>
buildItem(context, index, animation),
),
),
),
);
}
}
You are retrieving your provider from a StatelessWidget. As such, the ChangeNotifier can't trigger your widget to rebuild because there is no state to rebuild. You have to either convert ParentWidget to be a StatefulWidget or you need to get your provider using Consumer instead of Provider.of:
class ParentWidget extends StatelessWidget {
final GlobalKey<AnimatedListState> listKey = GlobalKey<AnimatedListState>();
#override
Widget build(BuildContext context) {
return Consumer<MainProvider>(
builder: (BuildContext context, MainProvider mainProvider, _) {
...
}
);
}
As an aside, the way you are using provider is to add the MainProvider to its provider and then retrieve it from within its immediate child. If this is the only place you are retrieving the MainProvider, this makes the provider pattern redundant as you can easily just declare it within ParentWidget, or even just get your list of images using a FutureBuilder. Using provider is a good step toward proper state management, but also be careful of over-engineering your app.