How to create an animated container that hide/show widget in flutter - flutter

I wanted to create a Container which looks like a Card with a small icon, when this icon is clicked the container height changed and show different component inside.
here is the expected result

Here is the working example,
double _height = 50.0;
bool _isExpanded = false;
Future<bool> _showList() async {
await Future.delayed(Duration(milliseconds: 300));
return true;
}
AnimatedContainer
AnimatedContainer(
duration: Duration(milliseconds: 300),
height: _height,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.grey,
),
width: MediaQuery.of(context).size.width - 100,
padding: EdgeInsets.only(left: 15, right: 15),
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Title'),
InkWell(
onTap: () {
if (!_isExpanded) {
setState(() {
_height = 300;
_isExpanded = true;
});
} else {
setState(() {
_height = 50;
_isExpanded = false;
});
}
},
child: Container(
height: 30,
width: 40,
color: Colors.red,
child: !_isExpanded ? Icon(Icons.add) : Icon(Icons.remove),
),
),
],
),
),
_isExpanded
? FutureBuilder(
future: _showList(), /// will wait untill box animation completed
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SizedBox();
}
return ListView.builder(
itemCount: 10,
shrinkWrap: true,
itemBuilder: (context, index) {
return Text('data'); // your custom UI
},
);
})
: SizedBox.shrink(),
],
),
);

Related

Find the width of every single item in list in flutter

I need to develope feature which paint the text by syllables (like screenshot shows). Bows and dots represent syllables (dot - 1 letter syllable, bow - 2 letter syllable). The painting is provided by dragging of green slider.
There is a variant of getting syllable position with the help of GlobalKey. I use the method List.generate for creating numerous GlobalKeys but get the exception Multiple widgets used the same GlobalKey. How can help me to resolve this task?
There is method for creating Row of Columns which include letter and bow or dot.
List<Widget> createDotAndBows(String sentence, List<GlobalKey> keys) {
DetailedScreenBloc _bloc = DetailedScreenBloc();
List<String> syllablesRow = [];
List<Widget> dotAndBows = [];
List<String> splittedText = sentence.split(' ');
for (int i = 0; i < splittedText.length; i++) {
syllablesRow.addAll(_bloc.syllables(splittedText[i]));
}
_syllablesTotal.add(syllablesRow.length);
for (int index = 0; index < syllablesRow.length; index++) {
dotAndBows.add(
(syllablesRow[index] != ' ')
? IntrinsicWidth(
key: keys[index],
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.only(
bottom: FairyTaleSizes.tinyPadding4,
),
child: Text(
syllablesRow[index],
style: FairyTaleStyle(
fontWeight: FontWeight.w800,
fontSize: getProportionateScreenWidth(22),
color: FairyTaleColors.fullBlack,
),
textAlign: TextAlign.center,
maxLines: 1,
),
),
(_bloc.getSyllableType(syllablesRow[index]) == 2)
? Padding(
padding: const EdgeInsets.symmetric(
horizontal: FairyTaleSizes.theMostTinyPadding2,
),
child: CustomPaint(
painter: BowPainter(),
child: Center(
child: Container(
height: getProportionateScreenHeight(20),
),
),
),
)
: (_bloc.getSyllableType(syllablesRow[index]) == 1)
? Center(
child: Container(
height: getProportionateScreenHeight(23),
width: getProportionateScreenHeight(23),
decoration:
const BoxDecoration(shape: BoxShape.circle, color: FairyTaleColors.fullBlack),
),
)
: Container(),
],
),
),
)
: Text(
' ',
key: keys[index],
),
);
}
return dotAndBows;
}
This is the implementation of the method above in UI
class DetailedScreen extends StatefulWidget {
final String? detailedBanner;
final List<String>? fullText;
const DetailedScreen({this.detailedBanner, this.fullText});
#override
State<DetailedScreen> createState() => _DetailedScreenState();
}
class _DetailedScreenState extends State<DetailedScreen> {
final ItemScrollController _itemScrollController = ItemScrollController();
final ItemPositionsListener _itemPositionsListener = ItemPositionsListener.create();
int currentIndex = 1;
final _bloc = DetailedScreenBloc();
List<GlobalKey> keysList = [];
final GlobalKey _sliderKey = GlobalKey();
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
_bloc.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SizedBox(
height: MediaQuery.of(context).size.height,
child: SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(),
child: Stack(
children: <Widget>[
Container(
width: SizeConfig.screenWidth,
height: SizeConfig.screenHeight,
decoration: const BoxDecoration(
color: FairyTaleColors.lightGold,
),
),
Column(
children: [
Align(
alignment: Alignment.topCenter,
child: Container(
height: SizeConfig.screenHeight / 2,
width: SizeConfig.screenWidth,
decoration: BoxDecoration(
image: DecorationImage(
image: Image.asset(widget.detailedBanner ?? '').image,
fit: BoxFit.fitWidth,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Align(
alignment: Alignment.topLeft,
child: ArrowWidget(
height: getProportionateScreenHeight(84),
width: getProportionateScreenWidth(36),
isForward: false,
onTap: () => Navigator.of(context).pop(),
),
),
StreamBuilder<bool>(
stream: _bloc.isVoiceOnStream,
builder: (context, snapshot) {
bool? _isVoiceOn = snapshot.data;
return Padding(
padding: const EdgeInsets.only(
right: FairyTaleSizes.bigHorizontalPadding36,
),
child: Align(
alignment: Alignment.topRight,
child: VoiceSwitcher(
isVoiceOn: _isVoiceOn,
onPressed: () {
if (_isVoiceOn != null && _isVoiceOn) {
_bloc.switchVoice(false);
} else {
_bloc.switchVoice(true);
}
}),
),
);
}),
],
),
),
),
Padding(
padding: const EdgeInsets.only(
top: FairyTaleSizes.middleHorizontalPadding22,
),
child: Stack(
children: [
StreamBuilder<int>(
stream: _bloc.syllablesTotalStream,
builder: (context, snapshot) {
return SizedBox(
height: MediaQuery.of(context).size.height,
child: ScrollablePositionedList.builder(
shrinkWrap: true,
padding: const EdgeInsets.only(
bottom: FairyTaleSizes.twoHundredPadding216,
),
physics: const NeverScrollableScrollPhysics(),
itemScrollController: _itemScrollController,
itemPositionsListener: _itemPositionsListener,
itemCount: widget.fullText!.length,
itemBuilder: (_, index) {
int total = snapshot.data ?? 0;
keysList.addAll(
List.generate(
total,
(index) => GlobalKey(),
),
);
print('$index - $keysList');
return Container(
padding: const EdgeInsets.only(
bottom: FairyTaleSizes.itemsMassivePadding140,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: _bloc.createDotAndBows(
widget.fullText![index],
keysList,
),
),
);
},
),
);
}),
StreamBuilder<double>(
initialData: 0.0,
stream: _bloc.shadowPositionStream,
builder: (context, snapshot) {
double _position = snapshot.data ?? 0.0;
return Positioned(
left: _position,
child: Container(
color: FairyTaleColors.lightGold.withOpacity(0.9),
height: getProportionateScreenWidth(23),
width: MediaQuery.of(context).size.width,
),
);
}),
StreamBuilder<List>(
stream: CombineLatestStream.list([
_bloc.sliderValueStream,
_bloc.shadowPositionStream,
]),
builder: (context, snapshot) {
double _sliderValue = snapshot.data?[0] ?? 0.0;
double _shadowPosition = snapshot.data?[1] ?? 0.0;
return Padding(
padding: const EdgeInsets.symmetric(
vertical: FairyTaleSizes.hundredPadding100,
horizontal: FairyTaleSizes.massivePadding64,
),
child: SliderTheme(
data: const SliderThemeData(
trackShape: GradientRectSliderTrackShape(),
trackHeight: 14.0,
thumbShape: GradientSliderThumbShape(
enabledThumbRadius: 16,
pressedElevation: 5.1,
),
),
child: Slider(
key: _sliderKey,
min: 0.0,
max: 200.0,
value: _sliderValue,
inactiveColor: FairyTaleColors.inactiveGrey,
onChanged: (value) {
_sliderValue = value;
_shadowPosition = value * 4.5;
_bloc.changeSliderValue(_sliderValue);
_bloc.stepBySyllable(keysList);
// _bloc.changeShadowPosition(_shadowPosition);
},
onChangeEnd: (value) {
if (value == 200) {
keysList.clear();
_bloc.changeSliderValue(0.0);
_shadowPosition = 0;
_bloc.scrollString(_itemScrollController, currentIndex);
_bloc.changeShadowPosition(0.0);
currentIndex++;
}
},
),
),
);
}),
],
),
),
],
),
],
),
),
),
);
}
}

How to change position of Container inside Stack?

Im trying to displaying a button inside my stack but it not getting the correct position. The button is the reply Button . I added a foot how it looks at the moment you can check it what I want is displaying it on the right side of the window at the bottom with a bit of spacing between bottom and the button.
Hope anyone can help. if you need more information please leave a comment .
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
try {
return Scaffold(
body: StreamBuilder(
stream: mystreamofallvideos,
builder: (context, snapshot) {
if (snapshot.hasData &&
snapshot.connectionState != ConnectionState.waiting) {
return PageView.builder(
itemCount: snapshot.data.docs.length,
controller:
PageController(initialPage: 0, viewportFraction: 1),
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
DocumentSnapshot videos = snapshot.data.docs[index];
return Stack(children: [
Videoplayeritem(widget.videoid),
Column(children: [
Align(
alignment: Alignment.bottomLeft,
child: Container(
height: 100,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
IconButton(
icon: Icon(
Icons.close,
color: Colors.white,
size: 35,
),
onPressed: () {
Navigator.of(context).pop();
}),
SizedBox(
width: 190,
),
],
),
),
),
Container(
color: Colors.red,
width: 210,
height: 94,
//color: Colors.blue.withOpacity(0.5),
child: InkWell(
onTap: () => sharevideo(
widget.videoid, videos.data()['id']),
child: Icon(Icons.reply,
size: 55, color: Colors.white),
),
),
]),
//starssonthe right
]);
});
} else {
return Center(child: CircularProgressIndicator());
}
}),
);
} catch (e) {
e.toString();
}
}
}
This is how it looks
enter image description here
Wrap it in an align and add a padding to the bottom:
Align(
alignment: Alignment.bottomRight,
child: Container(
height: 40,
padding: const EdgeInsets.only(bottom: 16),
child: OutlinedButton(
onPressed: () {},
child: Text('mybutton'),
),
)
you can wrap your container with either Positioned or Align widgets
like :
Positioned(
top: 0.0,
left: 0.0,
child: Icon(Icons.message,
size: 128.0, color: Colors.greenAccent[400]), //Icon
),

Flutter : how to hide and show button on last and first index in listView

i set two buttons(left and right Button) on top of ListView. buttons work for scrolling on click. now i want to hide the left button when index is 0 and the right button when index is last. more explain to clear, the left button will be hidden in first index and the right button will be hidden in last index. please help me.
class ScrollingLeftAndRightButtonHide extends StatefulWidget {
#override
_ScrolllingOnClickButtonState createState() =>
_ScrolllingOnClickButtonState();}
class _ScrolllingOnClickButtonState
extends State<ScrollingLeftAndRightButtonHide> {
final _controller = ScrollController();
var _width = 100.0;
#override
Widget build(BuildContext context) {
var sizeDevice = MediaQuery.of(context).size;
this._width = sizeDevice.width;
var recentIndexIncrease = 0;
var recentIndexDecrease = 0;
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Column(
children: <Widget>[
Expanded(
flex: 1,
child: Container(
color: Colors.green,
)),
Expanded(
flex: 2,
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: ClipOval(
child: Material(
color: Colors.blue, // button color
child: InkWell(
splashColor: Colors.red, // inkwell color
child: SizedBox(
width: 56,
height: 56,
child: Icon(Icons.arrow_back)),
onTap: () {
var recentIndexDecreaseMinus =
recentIndexDecrease--;
_animateToIndex(recentIndexDecrease);
},
),
),
),
),
Expanded(
flex: 2,
child: Container(
color: Colors.transparent,
)),
Padding(
padding: const EdgeInsets.only(right: 8),
child: ClipOval(
child: Material(
color: Colors.blue, // button color
child: InkWell(
splashColor: Colors.red, // inkwell color
child: SizedBox(
width: 56,
height: 56,
child: Icon(Icons.arrow_forward)),
onTap: () {
_animateToIndex(recentIndexIncrease);
},
),
),
),
),
],
)),
Expanded(
flex: 16,
child: Container(
// height: 400,
child: ListView.builder(
controller: _controller,
scrollDirection: Axis.horizontal,
physics: PageScrollPhysics(),
itemCount: word_data.drink.length,
itemBuilder: (BuildContext context, int index) {
recentIndexIncrease = index;
recentIndexDecrease = index;
var wordDataReplace = word_data.drink[index]
.replaceAll(" ", "_")
.toLowerCase();
return Container(
child: Column(
children: <Widget>[
Expanded(
flex: 6,
child: GestureDetector(
child: Container(
color: Colors.purple,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Image.asset(
"asset/drink_images/" +
wordDataReplace +
".png",
fit: BoxFit.contain,
),
),
),
)),
],
),
width: sizeDevice.width,
);
}),
color: Colors.yellow,
),
),
],
),
),
);
}
_animateToIndex(i) => _controller.animateTo(_width * i,
duration: Duration(seconds: 1), curve: Curves.fastOutSlowIn);
}
this image of (ListView with top two Button)
I think it might be easier for you to replace ListView.builder by a Flutter_Swiper it will make your life a lot easier. Or maybe you can add a listner to your ScrollController in the initState where it handles the value of two Boolean variables leftButtonEnabled and rightButtonEnabled and set them to true or false depending on the position of the Controller
EDIT :
here's an example of using Flutter swiper in your code, I tried to make it simple and in the same time adding multiple features that can help you ( like SwiperControl ) I hope it helps you a little bit.
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
home: ScrollingLeftAndRightButtonHide(),
),
);
}
class ScrollingLeftAndRightButtonHide extends StatefulWidget {
#override
_ScrolllingOnClickButtonState createState() =>
_ScrolllingOnClickButtonState();
}
class _ScrolllingOnClickButtonState
extends State<ScrollingLeftAndRightButtonHide> {
SwiperController _controller = SwiperController();
SwiperControl _control = SwiperControl(color: Colors.white);
double get _width => MediaQuery.of(context).size.width;
double get _height => MediaQuery.of(context).size.height;
bool inFirstPage = true;
bool inLastPage = false;
List<String> word_data = [
"First",
"Second",
"Third",
"Fourth",
"Fifth",
"Sixth",
"Last",
];
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: Column(
children: <Widget>[
Container(
color: Colors.white,
child: Row(
children: <Widget>[
if (!inFirstPage)
IconButton(
color: Colors.indigoAccent,
onPressed: () {
_controller.previous();
},
icon: Icon(Icons.arrow_back),
),
Spacer(),
if (!inLastPage)
IconButton(
color: Colors.indigoAccent,
onPressed: () {
_controller.next();
},
icon: Icon(Icons.arrow_forward),
),
],
),
),
Expanded(
child: Container(
color: Colors.white,
child: Swiper(
controller: _controller,
control: _control,
loop: false,
scrollDirection: Axis.horizontal,
itemCount: word_data.length,
onIndexChanged: (value) {
if (value == word_data.length - 1)
setState(() {
inLastPage = true;
});
else if (value == 0)
setState(() {
inFirstPage = true;
});
else {
setState(() {
inFirstPage = false;
inLastPage = false;
});
}
},
itemBuilder: (BuildContext context, int index) {
return Container(
child: Column(
children: <Widget>[
Expanded(
child: GestureDetector(
child: Container(
width: _width,
alignment: Alignment.center,
color: Colors.indigoAccent,
child: Text(word_data[index]),
),
),
),
],
),
);
},
),
),
),
],
),
),
);
}
}
Add two variables in your state as
class _ScrolllingOnClickButtonState
extends State<ScrollingLeftAndRightButtonHide> {
bool leftEnabled = false; //this is initial visibility of left button
bool rightEnabled = true; //this is initial visibility of right button
........
Then in your build function where you are displaying left and right button add if statement
#override
Widget build(BuildContext context) {
var sizeDevice = MediaQuery.of(context).size;
this._width = sizeDevice.width;
var recentIndexIncrease = 0;
var recentIndexDecrease = 0;
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Column(
.............
if(leftEnabled)
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: ClipOval(
child: Material(
color: Colors.blue, // button color
child: InkWell(
splashColor: Colors.red, // inkwell color
child: SizedBox(
width: 56,
height: 56,
child: Icon(Icons.arrow_back)),
onTap: () {
var recentIndexDecreaseMinus =
recentIndexDecrease--;
_animateToIndex(recentIndexDecrease);
if (index == 0) { //Your logic to detect start of the list.
leftEnabled = false; //if it is the start make left invisible
}
if(list.size > 1)
rightEnabled = true; //whenever left button is pressed and your data has more than 1 element make right visible
setState(() {});
},
),
),
),
),
...............
Same code for the right button.
You cannot do it through your current structure of code. To achieve it you will have to move those arrow button Icons inside of the listView like this:
return ListView.builder(
scrollDirection: Axis.horizontal,
physics: PageScrollPhysics(),
itemCount: 5,
itemBuilder: (BuildContext context, int index) {
recentIndexIncrease = index;
recentIndexDecrease = index;
var wordDataReplace = word_data.drink[index].replaceAll(" ", "_").toLowerCase();
return Column(
children: <Widget>[
Row(
children: [
//Left arrow is the button indicating left arrow
if (index != 0) LeftArrow,
//Rightarrow is the button indicating right arrow
if (index != 4) RightArrow
],
),
Expanded(
child: GestureDetector(
child: Container(
color: Colors.purple,
padding: const EdgeInsets.all(10.0),
child: Image.asset("asset/drink_images/" +
wordDataReplace +
".png",
fit: BoxFit.contain,
),
),
)),
],
);
});

How to Implement a manual carousel slider in Flutter?

I am creating a product image carousel which contains pictures of shoes where the user can change the image to be viewed by selecting a different color.
The user can manually scroll through the images without an issue,however when I try to manually change the displayed carousel image, only the indicator changes, but the image remains on the first image.
class DetailsPage extends StatefulWidget {
final String url;
final String title;
final int index;
DetailsPage({this.url, this.title, this.index});
#override
_DetailsPageState createState() => _DetailsPageState();
}
class _DetailsPageState extends State<DetailsPage> {
List imgList = [
'https://i.dlpng.com/static/png/6838599_preview.png',
'https://www.manelsanchez.pt/uploads/media/images/nike-air-force-max-ii-blue-fury-18.jpg',
'https://www.vippng.com/png/detail/30-302339_nike-women-running-shoes-png-image-transparent-background.png',
];
int _current = 0;
String selected = "grey";
List<T> map<T>(List list, Function handler) {
List<T> result = [];
for (var i = 0; i < list.length; i++) {
result.add(handler(i, list[i]));
}
return result;
}
final CarouselController _buttonCarouselController = CarouselController();
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).canvasColor,
appBar: AppBar(
title: Center(
child: Text(
'Details',
style: TextStyle(
fontFamily: 'OpenSansLight',
fontSize: 26,
color: Theme.of(context).textTheme.headline1.color),
),
),
body: ListView(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
//Carousel Slider
CarouselSlider.builder(
options: CarouselOptions(
carouselController: _buttonCarouselController,
height: 200.0,
enlargeCenterPage: true,
enlargeStrategy: CenterPageEnlargeStrategy.height,
initialPage: 0,
reverse: false,
autoPlay: false,
enableInfiniteScroll: false,
scrollDirection: Axis.horizontal,
onPageChanged: (index, fn) {
setState(() {
_current = index;
});
}),
itemCount: imgList.length,
itemBuilder: (BuildContext context, int index) =>
Builder(builder: (BuildContext context) {
return Image.network(
imgList[index],
fit: BoxFit.contain,
);
}),
),
SizedBox(height: 10),
//Indicator to show current index of images
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: map<Widget>(imgList, (index, url) {
return Container(
width: 30.0,
height: 2.0,
margin: EdgeInsets.symmetric(
vertical: 10.0, horizontal: 4.0),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(10.0),
color: _current == index
? Colors.deepPurple
: Colors.grey,
),
);
}),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 30,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Color',
style: TextStyle(
fontFamily: 'OpenSansLight',
fontSize: 24)),
],
),
),
),
Flexible(
fit: FlexFit.loose,
child: Container(
width: width,
height: 120,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: imgList.length,
itemBuilder: (BuildContext context, int index) {
//Color selector from images to manually control the carousel
return GestureDetector(
onTap: () {
setState(() {
selected = imgList[index];
_current = index;
_buttonCarouselController
.animateToPage(_current);
print('I HAVE SELECTED $selected');
});
},
child: ColorTicker(
image: imgList[index],
selected: selected == imgList[index],
),
);
},
),
),
),
],
),
);
Color Ticker Widget
class ColorTicker extends StatelessWidget {
final image;
final bool selected;
ColorTicker({this.image, this.selected});
#override
Widget build(BuildContext context) {
print(selected);
return Container(
margin: EdgeInsets.all(5),
width: 100,
height: 100,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.scaleDown, image: NetworkImage(image)),
shape: BoxShape.circle,
border: selected
? Border.all(color: Colors.deepPurple, width: 3)
: Border.all(color: Colors.grey[500])),
// color: color.withOpacity(0.7)),
child: selected
? Center(child: Icon(Icons.check, size: 40, color: Colors.deepPurple))
: Container(),
);
}
}
I've tried all I could from the documentation : https://pub.dev/packages/carousel_slider/example
But I kept getting an error
Unhandled Exception: NoSuchMethodError: The getter 'options' was called on null
I am almost embarassed at my mistake.
In the configuration of the slider, I placed the controller in the wrong place.
I put the controller inside the Carousel options instead of under CarouselSlider
CarouselSlider(
carouselController: _buttonCarouselController,
options: CarouselOptions(
... ))
It now works :)

type 'Future<List<dynamic>>' is not a subtype of type 'Future<List<FoodModel>>'

So I'm trying to get my foodmodel data to show up on my screen, I don't know what is wrong with this code, it must be something about await async but I can't figure it out. It only says type Future<List<dynamic>> is not a subtype of type Future<List<FoodModel>>. I'm still new to flutter. Is there anyway to get data using async await from this code?
class FoodPage extends StatefulWidget {
#override
_FoodPageState createState() => _FoodPageState();
}
class _FoodPageState extends State<FoodPage> {
Future<List<FoodModel>> foods;
#override
initState() {
super.initState();
setState(() {
var db= DatabaseHelperFood();
foods=db.getFoods();
});
}
GridView food_data (List<FoodModel> foods)
{
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount: foods.length,
itemBuilder: (_, int position)
{
return Card(
child:Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(FoodModel.map(foods[position]).alamat),
fit: BoxFit.cover,
)),
child: Container(
margin: EdgeInsets.fromLTRB(
0, 152, 0, 0),
child: Column(
children: <Widget>[
Container(
width: 500,
height: 25,
child: RaisedButton(
onPressed: () {
},
child: Text('Beli : $FoodModel.map(_foods[position]).harga',
textAlign: TextAlign
.center,
style: TextStyle(
color: Colors.white)),
color: Colors.black,
))
],
)
)
),);
},
);
}
foodlist(){
return Expanded(
child:FutureBuilder(
future:foods,
builder:(context,datas)
{
if(datas.hasData)
{
return food_data(datas.data);
}
else if(null== datas.data || datas.data.length==0)
{
return Text("No data");
}
return CircularProgressIndicator();
}
)
);
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.grey[900],
leading: Icon(Icons.menu),
actions: <Widget>[
Padding(
padding: EdgeInsets.all(5),
child: Row(children: <Widget>[
Container(
child:Text("GoFlix",style:TextStyle(fontSize: 30)),
margin:EdgeInsets.only(right:90),
),
Container(
child: Icon(Icons.shopping_cart, size: 30),
margin: EdgeInsets.only(top: 5)),
Container(
margin: EdgeInsets.only(top: 5),
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.redAccent[800],
borderRadius: BorderRadius.circular(10)),
child: Center(child: Text("0")),
)
]))
]),
body:Container(
color:Colors.grey[800],
child: Column(
children: <Widget>[
Image.asset('Asset/Movieabanner.jpg'),
foodlist(),
])
)
);
}
}
If your Future value is List<FoodModel> you need to build your FutureBuilder as follows:
FutureBuilder<List<FoodModel>>(
future: foods,
builder: (context, datas) {
}
)
Since FutureBuilder handles async await things, instead of calling db.getFoods() inside your initState method, you can do it inside FutureBuilder as follows:
FutureBuilder<List<FoodModel>>(
future: db.getFoods(),
builder: (context, datas) {
}
)
But you are using foods in some other places, so you might need a little more refactoring.