I am not sure how to ask this question, therefore, bare with me.
first page displays a gridview of different items, when you click on one of the items it brings you to a description page of the item.
in this description page it uses futurebuilder where future: gets firebasefirestore.instance.collection......get()
it then follows with a builder:
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> documentData = snapshot.data.data();
//Add images
// imgList.clear();
imgList.add(documentData['item_images'][0]);
imgList.add(documentData['item_images'][1]);
imgList.add(documentData['item_images'][2]);
return ListView(
children: [
CarouselWithIndicatorDemo(),
],);
}
The CarouselWithIndicatorDemo() is straight from the Dart dev carousel_slider example.
Retrieving the data works perfectly fine and the carousel displays all 3 images from the imglist (seen above).
but when I go back to the previous page to click on another item, the images in the carousel do not update. I tried imgList.removeAt(0) 3 times to clear the list within the dispose:
#override
void dispose() {
imgList.removeAt(0);
imgList.removeAt(0);
imgList.removeAt(0);
super.dispose();
}
but that didn't work... how can I update this list correctly?
***************** EDIT *********************
in a dart file I am passing the following information:
Map<String, dynamic> documentData = snapshot.data.data();
List imageList = documentData['item_images'];
This is within my ListView( children:[
ImageSwipe(imageList: imageList) // instead of CarouselWithIndicatorDemo()
The other dart file:
class ImageSwipe extends StatefulWidget {
ImageSwipe({Key key, this.imageList}) : super(key: key);
final List imageList;
#override
_ImageSwipeState createState() => _ImageSwipeState();
}
class _ImageSwipeState extends State<ImageSwipe> {
int _selectedPage = 0;
#override
Widget build(BuildContext context) {
return Container(
height: 400.0,
child: Stack(
children: [
PageView(
onPageChanged: (value) {
setState(() {
_selectedPage = value;
});
},
children: [
for (var i = 0; i < widget.imageList.length; i++)
Container(
child: FadeInImage.assetNetwork(
placeholder: 'assets/missingImage.jpg',
image: widget
.imageList[i],
fit: BoxFit.cover,
),
),
],
),
Positioned(
bottom: 10.0,
left: 0.0,
right: 0.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
for (var i = 0; i < widget.imageList.length; i++)
AnimatedContainer(
duration: Duration(
milliseconds: 300,
),
curve: Curves.easeOutCubic,
margin: EdgeInsets.symmetric(horizontal: 5.0),
width: _selectedPage == i ? 36.0 : 10.0,
height: 10.0,
decoration: BoxDecoration(
color: AppColors.primaryColor,
borderRadius: BorderRadius.circular(
12.0,
),
),
)
],
),
),
]),
);
}
}
I have resolved and issue like that by using this:
final backgroundImages = ['signin_background.png','limpieza.jpg',/*'medicina.jpg',*/'plomero.jpg','profesor.jpg','veterinario.jpg'];
Then wrapping it in a animatedSwitcher like this:
Stack(
children: [
AnimatedSwitcher(
duration: Duration(milliseconds: 800),
transitionBuilder: (Widget image, Animation<double> animation) {
return FadeTransition(opacity: animation, child: image,);
},
child: Image.asset('assets/'+backgroundImages[pos],
width: MediaQuery.of(context).size.width,
key: ValueKey(pos),
fit: BoxFit.fill,
),
),
So you have to first fetch the images from your db or store them withing the app.
Related
I have a list like this a = [{'one': 'one', 'two': null, 'three': [{'four': 'four'}]}]
I send it to a function to use it in a post request which in the body should receive a Map, so what I did was this to a[0], the problem is that I get this error The getter 'length' was called on null
I start to review and it treats all the property values as if they were Strings, even the nested list 'three': [{'four': 'four'}], I have tried to send the post in this way http.post (url, body: (recurrence [0] as Map)) but it has not worked, it always gives me the same error, even if in the body I put the properties by hand in the body: {'new property': a [0] [' tres']}, how should one act to solve this problem? Thank you very much for your help
Code:
void _ordersGet() async {
await http.get(url).then((value) {
setState(() {
orders = jsonDecode(value.body);
}
}
orders is sent to a new widget: orderList(orders)
orderList is a listView
ListView.builder(
shrinkWrap: true,
primary: false,
itemCount: orders.length,
itemBuilder: (orders, index) {
return return Card(
elevation: 5,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(orders[index]['facts']),
SizedBox(
width: 4,
),
Text('Cantidad : '),
Text(orders[index]['ITEMS'][0]['jeans']),
SizedBox(
width: 4,
),
IconButton(
onPressed: () => _reorderData(context, orders[index]),
icon: Icon(
Icons.replay_outlined,
color: Theme.of(context).accentColor,
)),
],
),
);
},
);
_reorderData is a function that make a get request, the info in shipped to ReorderModal
ReorderModal it only shows the information and has a button
void _reorderData(BuildContext ctx, order) async {
var data;
var url = 'serverAddress/${order['facts']}';
await http.get(url).then((value) {
data = jsonDecode(value.body);
data[0]['CORPORATION'] = order['corporation'];
showModalBottomSheet(
context: ctx,
builder: (_) {
return ReorderModal(data);
});
}).catchError((onError) {});
}
class ReorderModal extends StatelessWidget {
final List data;
ReorderModal(this.data);
void orderSend(orderInfo) async {
var url = 'serverAddress';
await http.post(url, body: orderInfo[0]).then((value) {
print(jsonDecode(value.body));
}).catchError((onError) {
print(onError);
});
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(10),
child: Column(children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Column(
children: [
ElevatedButton(
onPressed: () {
orderSend(data);
//print(data);
},
child: Text('ONE Click'))
]),
);
}
}
when i press the ONE Click button execute the function orderSend, orderSend make a post request and the problem described above
This is the simplified code, I know it must be something very simple, but it is giving me a lot of work to solve
The idea behind my code is to populate a Column widget with dynamic data I get from a list of objects
I use a List>> that's essentially just a list of objects.
My List :
List<List<Map<String, String>>> listCardsAll = [
[
{
"cardCate": "AMEX",
"cardDesc": "American Platinum 6",
"cardImg":
"images/AMEX/American-Express®-Green-Card-Earn-Rewards-Points.png"
}
],
[
{
"cardCate": "AMEX",
"cardDesc": "American Platinum 5",
"cardImg":
"images/AMEX/American-Express®-Green-Card-Earn-Rewards-Points.png"
}
],
];
Then I call a function within a column that returns a Widget(I want to return a List but it gives an error)
Widget:
Column(
children: <Widget>[
Row(
children: <Widget>[generateCardsALL()],
)
],
)
I Use a for-loop then in the function a make a widget with that dynamic data but it only returns one widget rather than the Collection that i was hoping for.
my Function :
Widget generateCardsALL() {
var count = 0;
for (var item in listCardsAll) {
count++;
if (count <= 2) {
return ReusableCards(
cardName: item[0]["cardDesc"],
cardLink: item[0]["cardImg"],
cardRowNum: count,
);
} else {
count = 0;
return ReusableCards(
cardName: item[0]["cardDesc"],
cardLink: item[0]["cardImg"],
cardRowNum: 3,
);
}
}
}
(The cardRowNum is only to see when its 3 cards next to each other that it can generate a new row)
This is the ReusableCards
ReusableCards:
class ReusableCards extends StatelessWidget {
final String cardLink;
final int cardRowNum;
final String cardName;
ReusableCards(
{#required this.cardLink,
#required this.cardRowNum,
#required this.cardName});
#override
Widget build(BuildContext context) {
// addToListcards(cardLink);
print("Inserted");
return (cardRowNum == 1 || cardRowNum == 2
? GestureDetector(
onDoubleTap: () {},
child: Padding(
padding: EdgeInsets.fromLTRB(0, 15, 15, 20),
child: Container(
width: MediaQuery.of(context).size.width * 0.24,
child: SizedBox(
child: Column(
children: <Widget>[
Image.asset(cardLink, fit: BoxFit.fill),
Text(cardName)
],
),
),
),
),
)
: cardRowNum == 3
? Padding(
padding: EdgeInsets.fromLTRB(0, 15, 0, 20),
child: Container(
width: MediaQuery.of(context).size.width * 0.24,
child: SizedBox(
child: Column(
children: <Widget>[
Image.asset(cardLink, fit: BoxFit.fill),
Text("" + cardRowNum.toString())
],
),
),
),
)
: SizedBox());
}
}
if I want to make it a List rather then just a widget it breaks. Can someone please help me with this dilemma
Try using map for iterating through the list and getting a list of widgets,
Example:
Column(
children: listCardsAll.map((oneCard){
return Container(
child: Text(oneCard.cardDesc)
);
}).toList(),
)
I think the problem is that inside of the function generateCardsALL. You don't return an array of Widgets, you should change to this.
List<Widget> generateCardsALL() {
var count = 0;
List<Widget> widgets;
for (var item in listCardsAll) {
count++;
if (count <= 2) {
widgets.add(ReusableCards(
cardName: item[0]["cardDesc"],
cardLink: item[0]["cardImg"],
cardRowNum: count,
));
} else {
count = 0;
widgets.add(ReusableCards(
cardName: item[0]["cardDesc"],
cardLink: item[0]["cardImg"],
cardRowNum: 3,
));
}
}
return widgets;
}
I have a mixed list of text and images and I would like to place the applicable text and image together on one card. The current code works for text however, when I try to add the image I always get an error. Does anyone know how to do this?
Any help is appreciated!
class Episode {
String seasonEpisode;
String airDate;
Image epImage;
Episode({this.seasonEpisode, this.airDate, this.epImage});
}
class EpisodeList extends StatefulWidget {
/*final Episode episodes;*/
#override
_EpisodeListState createState() => _EpisodeListState();
}
class _EpisodeListState extends State<EpisodeList> {
List<Episode> episodes = [
Episode(seasonEpisode: 'S24:E1', airDate: 'February 18, 2020', epImage: Image.asset('assets/Bachelor1.jpeg')),
Episode(seasonEpisode: 'S24:E2', airDate: 'February 25, 2020', epImage: Image.asset('assets/Bachelor1.jpeg')),
Episode(seasonEpisode: 'S24:E3', airDate: 'February 31, 2020', epImage: Image.asset('assets/Bachelor1.jpeg')),
];
Widget epCardTemplate(episode) {
return Card(
margin: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Image.asset(episode.epImage),
Text(
episode.seasonEpisode
),
SizedBox(height: 6.0),
Text(
episode.airDate
),
],
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: DARK_GREY_COLOR,
body: Column(
children: episodes.map((episode) => epCardTemplate(episode)).toList(),
)
);
}
}
So what you are doing in your code is equivalent to
children: <Widget>[
Image.asset(Image.asset('assets/......')),
Text(
episode.seasonEpisode
),
SizedBox(height: 6.0),
Text(
episode.airDate
),
],
Basically, you are putting an image inside another image widget.
I'm using the TMDb API to get image urls to display. I am able to get the image urls and display them on the console. But then when I try to create a method and loop through for each of the items in the list it keeps returning empty (i checked with print).
Edit: Both methods are inside the same class and literally right below each other.
Any help will be appreciated!
List<String> popularMovie = List<String>();
#override
void initState() {
super.initState();
this.getJsonData();
}
//GET POPULAR MOVIE INFO WITH API
Future<List> getJsonData() async {
http.Response response = await http.get(
Uri.encodeFull(popularURL),
headers: {
'Accept': 'application/json'
}
);
var popularMovieData = json.decode(response.body);
var placeholder = popularMovieData['results'];
//get a list of images only
for(var item in placeholder) {
popularMovie.add(item['poster_path']);
}
print(popularMovie.length); //20
print(popularMovie); //prints [imgURL, imageURL, ...]
return popularMovie;
} //end of popular movie api function
Below is the method that is suppose to loop through list items
//method to iterate through each item and get the image url to display image
List<Widget> popularMovies() {
List<Widget> popularMovieList = new List();
for(var item in popularMovie) { //this is empty
var popularMovieItem = Padding(
padding: EdgeInsets.all(10),
child: Container(
width: 250,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.4),
spreadRadius: 4,
blurRadius: 4,
),
]
),
child: Stack(
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height/2 - 20,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(15),),
image: DecorationImage(
image: NetworkImage('https://image.tmdb.org/t/p/w500${item}'),
fit: BoxFit.fill,
)
),
),
],
),
],
),
),
);
popularMovieList.add(popularMovieItem);
}
return popularMovieList;
}
And finally, I'd like to display all the movies on my page as
children:popularMovies(),
Since getJsonData is an async function, you need to use a FutureBuider or else instead of returning popularMovie you need to call setState
FutureBuilder<String>(
future: getJsonData,
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Press button to start.');
case ConnectionState.active:
case ConnectionState.waiting:
return Text('Awaiting result...');
case ConnectionState.done:
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
return Text('Result: ${snapshot.data}');
}
return null; // unreachable
},
)
I finally figured it out! It is super easy with setState so if anyone needs a solution to convert a
Future<List<String>> to List<String> and then use it as a normal List inside the scaffold here's what I did:
First, declare your list variable:
List<String> popularMovie = List<String>(); //declare a list inside the class
Then do your http call and assign the 'list of items you want' to your previously declared list variable 'inside setState'
#override
void initState() {
super.initState();
this.getJsonData();
}
//GET POPULAR MOVIE INFO WITH API
Future<List<String>> getJsonData() async {
http.Response response = await http.get(
Uri.encodeFull(popularURL),
headers: {
'Accept': 'application/json'
}
);
setState(() { //only get the first 10 movie images
var popularMovieData = json.decode(response.body);
for (int i = 0; i < 10; i++) {
popularMovie.add(popularMovieData['results'][i]['poster_path']);
}
print(popularMovie);
});
} //end of popular movie api function
Then I created a method to create a widget to display each image which is the same as the method I created in my original post that starts like this:
List<Widget> popularMovies() {
And finally, I wanted to display it this way(which you can do however you want to):
Padding(
padding: EdgeInsets.only(left: 10, top: 10, bottom: 10),
child: Container(
height: MediaQuery.of(context).size.height/2,
child: ListView(
scrollDirection: Axis.horizontal,
children: popularMovies(), //display all images in a horizontal row
),
),
),
And you're done!! :)
I am using Flutter table calendar plugin to make a calendar. In order to put events into the calendar, I have to add data to _events map. I want to get the data from Firestore document, and put the data into _events map. However, I don't know how to do it. I search everywhere but I can't get an answer.
This is my code
class _MemberEventsState extends State<MemberEvents>
with TickerProviderStateMixin {
Map<DateTime, List> _events;
List _selectedEvents;
AnimationController _animationController;
CalendarController _calendarController;
List<String> list = List();
#override
void initState() {
super.initState();
final _selectedDay = DateTime.now();
Firestore.instance
.collection('events')
.document('2019-07-30')
.get()
.then((DocumentSnapshot ds) {
list = List.from(ds['title']);
});
_events = {DateTime.parse("2019-08-01"): list};
_selectedEvents = _events[_selectedDay] ?? [];
_calendarController = CalendarController();
_animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 400),
);
_animationController.forward();
}
#override
void dispose() {
_animationController.dispose();
_calendarController.dispose();
super.dispose();
}
void _onDaySelected(DateTime day, List events) {
print('CALLBACK: _onDaySelected');
setState(() {
_selectedEvents = events;
});
}
void _onVisibleDaysChanged(
DateTime first, DateTime last, CalendarFormat format) {
print('CALLBACK: _onVisibleDaysChanged');
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
_buildTableCalendar(),
const SizedBox(height: 8.0),
const SizedBox(height: 8.0),
Expanded(child: _buildEventList()),
],
),
);
}
Widget _buildTableCalendar() {
return TableCalendar(
calendarController: _calendarController,
events: _events,
startingDayOfWeek: StartingDayOfWeek.sunday,
calendarStyle: CalendarStyle(
selectedColor: Colors.deepOrange[400],
todayColor: Colors.blueAccent[200],
markersColor: Colors.brown[700],
outsideDaysVisible: false,
),
headerStyle: HeaderStyle(
formatButtonTextStyle:
TextStyle().copyWith(color: Colors.white, fontSize: 15.0),
formatButtonDecoration: BoxDecoration(
color: Colors.deepOrange[400],
borderRadius: BorderRadius.circular(16.0),
),
),
onDaySelected: _onDaySelected,
onVisibleDaysChanged: _onVisibleDaysChanged,
);
}
Widget _buildEventList() {
return ListView(
children: _selectedEvents
.map((event) => Container(
decoration: BoxDecoration(
border: Border.all(width: 0.8),
borderRadius: BorderRadius.circular(12.0),
),
margin:
const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
child: ListTile(
title: Text(event.toString()),
),
))
.toList(),
);
}
}
So in the first step to achieve my goal, I made a document named 2019-07-30, then I made an array in it named title. Then I tried to get the values in the array to a List named list. However, list returned null.
I don't know where I went wrong.
I am new to Flutter, so the question might seem stupid.
Also, I am new to stackoverflow, so if I did any steps wrong on describing the question, please tell me so I can fix it.