Related
i'm trying to integrate a listView.builder in my UI! First of all, the whole content of the screen is inside a CustomScrollView that has silver widgets inside of it. Everything works pretty fine unless that my listview is not scrolling.
Here is the code:
class _DashboardScreenState extends State<DashboardScreen> {
#override
Widget build(BuildContext context) {
final screenHeight = MediaQuery.of(context).size.height;
return Scaffold(
appBar: CustomAppBar(),
body: CustomScrollView(
physics: ClampingScrollPhysics(),
slivers: <Widget>[
_buildHeader(screenHeight),
_buildBody(screenHeight),
],
),
);
}
}
The _buildBody code:
SliverToBoxAdapter _buildBody(double screenHeight) {
return SliverToBoxAdapter(
child: Column(
children: [
Container(
width: 100,
height: 65,
child: Padding(
padding: const EdgeInsets.only(top: 20),
child: ElevatedButton(
onPressed: () {},
child: Text(
'Add',
style: TextStyle(fontSize: 18),
),
style: ElevatedButton.styleFrom(
shape: StadiumBorder(),
backgroundColor: Palette.primaryColor),
),
),
),
SizedBox(
height: 10,
),
ListView.builder(
scrollDirection: Axis.vertical,
physics: const AlwaysScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: 6,
itemBuilder: ((BuildContext context, int index) {
return Container(
margin: const EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 20.0,
),
padding: const EdgeInsets.all(10.0),
height: screenHeight * 0.15,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xFFAD9FE4), Palette.primaryColor],
),
borderRadius: BorderRadius.circular(20.0),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Image.asset(
"assets/worker.png",
height: 80,
width: 80,
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Somme: 50 €',
style: const TextStyle(
color: Colors.white,
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: screenHeight * 0.01),
Text(
'Date: 19 novembre 2022',
style: TextStyle(fontSize: 10, color: Colors.white),
),
SizedBox(height: screenHeight * 0.01),
Text(
'Follow the instructions\nto do your own test.',
style: const TextStyle(
color: Colors.white,
fontSize: 16.0,
),
maxLines: 2,
),
],
)
],
),
);
}))
],
),
);
}
I tried adding shrinkWrap: true as well as the scroll direction. Also tried wrapping it inside a SingleScrollChildView, none of the solutions worked for me. I appreciate any kind of help!
You can use physics: const NeverScrollableScrollPhysics(), on listView, the parent widget is already handling the scroll event. But you can replace listView with Column widget.(we already have on parent, therefor using loop)
SliverToBoxAdapter _buildBody(double screenHeight) {
return SliverToBoxAdapter(
child: Column(
children: [
Container(
width: 100,
height: 65,
child: Padding(
padding: const EdgeInsets.only(top: 20),
child: ElevatedButton(
onPressed: () {},
child: Text(
'Add',
style: TextStyle(fontSize: 18),
),
style: ElevatedButton.styleFrom(
shape: StadiumBorder(),
backgroundColor: Palette.primaryColor),
),
),
),
SizedBox(
height: 10,
),
for (int i = 0; i < 6; i++)
Container(
margin: const EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 20.0,
),
padding: const EdgeInsets.all(10.0),
height: screenHeight * 0.15,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xFFAD9FE4), Palette.primaryColor],
),
borderRadius: BorderRadius.circular(20.0),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Image.asset(
"assets/worker.png",
height: 80,
width: 80,
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Somme: 50 €',
style: const TextStyle(
color: Colors.white,
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: screenHeight * 0.01),
Text(
'Date: 19 novembre 2022',
style: TextStyle(fontSize: 10, color: Colors.white),
),
SizedBox(height: screenHeight * 0.01),
Text(
'Follow the instructions\nto do your own test.',
style: const TextStyle(
color: Colors.white,
fontSize: 16.0,
),
maxLines: 2,
),
],
)
],
),
)
],
),
);
}
Instead of using ListView.Builderinside CustomScrollView. It is always better to use Slivers. Therefore, instead of wrapping ListView.builder with SliverToBoxAdapter, use SliverList. Here is the detail code I have refactored below for you. Or you can directly visit this link where you can play with the refactored code.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.light(),
home: const DashboardScreen(),
debugShowCheckedModeBanner: false,
);
}
}
class DashboardScreen extends StatefulWidget {
const DashboardScreen({super.key});
#override
State<DashboardScreen> createState() => _DashboardScreenState();
}
class _DashboardScreenState extends State<DashboardScreen> {
#override
Widget build(BuildContext context) {
final screenHeight = MediaQuery.of(context).size.height;
return Scaffold(
appBar: AppBar(),
body: CustomScrollView(
physics: ClampingScrollPhysics(),
slivers: <Widget>[
// your build header widget
SliverToBoxAdapter(
child: Container(
width: 100,
height: 65,
child: Padding(
padding: const EdgeInsets.only(top: 20),
child: ElevatedButton(
onPressed: () {},
child: Text(
'Add',
style: TextStyle(fontSize: 18),
),
style: ElevatedButton.styleFrom(
shape: StadiumBorder(),
backgroundColor: Colors.red,
),
),
),
),
),
SliverToBoxAdapter(
child: SizedBox(height: 10),
),
SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
return Container(
margin: const EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 20.0,
),
padding: const EdgeInsets.all(10.0),
height: screenHeight * 0.15,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xFFAD9FE4), Colors.red],
),
borderRadius: BorderRadius.circular(20.0),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
// Image.asset(
// "assets/worker.png",
// height: 80,
// width: 80,
// ),
//
Container(
height: 80,
width: 80,
child: Text("A"),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Somme: 50 €',
style: const TextStyle(
color: Colors.white,
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: screenHeight * 0.01),
Text(
'Date: 19 novembre 2022',
style: TextStyle(fontSize: 10, color: Colors.white),
),
SizedBox(height: screenHeight * 0.01),
Text(
'Follow the instructions\nto do your own test.',
style: const TextStyle(
color: Colors.white,
fontSize: 16.0,
),
maxLines: 2,
),
],
)
],
),
);
}),
)
],
),
);
}
}
I'm pretty much self-tutoring flutter and I'm working on a personal project. I wrapped it to singlechildscrollview but it still produces the problem. The code below:
class ScheduleDetail extends StatefulWidget {
var data;
ScheduleDetail(this.data);
#override
// ScheduleDetail({Key key, this.todos}) : super(key: key);
_ScheduleDetailState createState() => _ScheduleDetailState();
}
class _ScheduleDetailState extends State<ScheduleDetail>{
String foos = 'One';
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
ScreenUtil.instance =
ScreenUtil(width: 750, height: 1425, allowFontScaling: true)
..init(context);
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
// title: Text("String Master"),
title: SvgPicture.asset('assets/images/Logo_small.svg'),
centerTitle: true,
backgroundColor: Colors.transparent,
),
body: BackgroundImageWidget(
child: Center(
child: Container(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
height: ScreenUtil.getInstance().setHeight(150),
),
Container(
padding: EdgeInsets.symmetric(
horizontal: ScreenUtil.getInstance().setWidth(40),
),
child: Text(
AppStrings.scheduleTitle,
style: TextStyles.appName,
textAlign: TextAlign.center,
),
),
Container(
height: ScreenUtil.getInstance().setHeight(50),
),
SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.82),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: ScreenUtil.getInstance().setWidth(40),
),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_buildTopCard(),
SizedBox(height: 10),
_buildTimeCard(),
SizedBox(height: 10),
ListTile(
title: Text(
"Calendar",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.green,
fontSize: 16
),
),
),
Container(color: Colors.grey, height: 1),
_buildNoticeExpansionTile(),
Container(color: Colors.grey, height: 1),
_buildMemoExpansionTile(),
],
)),
),
],
)
)
),
],
)),
)));
}
Widget _buildTopCard() {
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7.0),
),
elevation: 15,
child: ClipPath(
clipper: ShapeBorderClipper(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7.0))),
child: Stack(
children: <Widget>[
Container(
height: 150,
decoration: BoxDecoration(
border: Border(
top: BorderSide(color: Colors.green, width: 30)),
color: Colors.white,
),
alignment: Alignment.centerLeft,
child: Column(
children: <Widget>[
ListTile(
title: Text(widget.data['eventTitle'],
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.green,
),
),
subtitle: Text(
widget.data['location'],
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.grey.shade600
),
),
),
Container(
padding: EdgeInsets.only(left: 10, right: 10),
child:
Divider(color: Colors.grey),
),
Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: Row (
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
widget.data['startDate'] + " " + widget.data['timeStart'],
style: TextStyle(
color: Colors.grey.shade600,
fontStyle: FontStyle.italic,
fontSize: 14
),
),
Spacer(flex: 2),
Text(
widget.data['startDate'] + " " + widget.data['timeEnd'],
style: TextStyle(
color: Colors.grey.shade600,
fontSize: 14,
fontStyle: FontStyle.italic,
),
),
]
)
),
],
)
),
Positioned(
left: 10,
top: 7,
width: 325,
child: Container(
padding: EdgeInsets.only(bottom: 10, left: 5, right: 5),
color: Colors.transparent,
child: Row (
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
widget.data['startDate'],
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white, fontSize: 14),
),
Spacer(flex: 2),
Text(
widget.data['timeStart'],
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white, fontSize: 14),
),
],
)
),
),
],
)
),
);
}
Widget _buildTimeCard() {
return Container(
height: 125,
width: 400,
margin: EdgeInsets.all(5.0),
decoration: BoxDecoration(
color: Colors.black,
border: Border.all(
color: Colors.green,
width: 0.5,
),
borderRadius: BorderRadius.circular(7.0),
),
child: Center(
child: Text(
'TIME OF EVENT',
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white, fontSize: 14),
),
),
);
}
Widget _buildNoticeExpansionTile() {
return Theme(
data: Theme.of(context).copyWith(unselectedWidgetColor: Colors.white, accentColor: Colors.white),
child: ExpansionTile(
title: new Text(
"Notice",
style: TextStyle(
color: Colors.green,
fontSize: 16
),
),
backgroundColor: Colors.transparent,
children: <Widget>[
Container(
child: ListView.builder(
padding: EdgeInsets.all(0.0),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: widget.data['notice'] != null ? widget.data['notice'].length : 0,
itemBuilder: (BuildContext context, int index){
return
Padding(
padding: EdgeInsets.only(left: 15, bottom: 10),
child: Text(
"\u2022 " + widget.data['notice'][index],
style: TextStyle(
color: Colors.white,
fontSize: 14
),
)
);
}
)
),
]
)
);
}
Widget _buildMemoExpansionTile() {
return
Theme(
data: Theme.of(context).copyWith(unselectedWidgetColor: Colors.white, accentColor: Colors.white),
child: ExpansionTile(
title: new Text(
"Memo",
style: TextStyle(
color: Colors.green,
fontSize: 16
),
),
backgroundColor: Colors.transparent,
children: <Widget>[
ListView.builder(
padding: EdgeInsets.all(0.0),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: widget.data['memo'] != null ? widget.data['memo'].length : 0,
itemBuilder: (BuildContext context, int index){
return
Padding(
padding: EdgeInsets.only(left: 15, bottom: 10),
child: Text(
(index + 1).toString() + ". " + widget.data['memo'][index],
style: TextStyle(
color: Colors.white,
fontSize: 14
),
)
);
}
)
]
)
);
}
}
Perhaps my mistake could be from one of those objects that I have used. However, I can't figure it out even though I searched around the internet. My intention is when the expandable tiles have 'overlapped' the screen size, you would be able to scroll it all the way down.
Wrap the SingleChildScrollView in Expanded Widget.
You can make use of the flutter dev tools for identifying overlapping issues.
I simplified the scaffold then wrapped SingleChildScrollView within Flexible.
I am having problem when I used the scrollcontroller to controll the gridview. I am having the error ( type 'String' is not a subtype of type 'int' of 'index'). But it was perfectly working before using the scrollcontroller. I don't where i need to change in order to remove this error. I also check the other issues regarding this in stackoverflow but couldn't get it. Can anyone check and tell me what can be change here in order to remove the error and show the data and also if my condition is right for loading 10 data in every scroll end.
import 'dart:convert';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:gridview_screoll/grid_content.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'constant.dart';
class ScrollableGrid extends StatefulWidget {
#override
_ScrollableGridState createState() => _ScrollableGridState();
}
class _ScrollableGridState extends State<ScrollableGrid> {
List data = [];
bool isLoading = false;
ScrollController _scrollController;
int pageCount = 1;
#override
void initState() {
// TODO: implement initState
super.initState();
this.fetchTopProducts();
addItemIntoLisT(pageCount);
_scrollController = new ScrollController(initialScrollOffset: 5.0)
..addListener(_scrollListener);
}
_scrollListener() {
if (_scrollController.offset >=
_scrollController.position.maxScrollExtent &&
!_scrollController.position.outOfRange) {
setState(() {
isLoading = true;
if (isLoading) {
pageCount = pageCount + 1;
addItemIntoLisT(pageCount);
}
});
}
}
void addItemIntoLisT(var pageCount) {
for (int i = (pageCount * 10) - 10; i < pageCount * 10; i++) {
fetchTopProducts();
isLoading = false;
}
}
#override
void dispose() {
_scrollController.dispose();
super.dispose();
}
fetchTopProducts() async {
setState(() {
isLoading = true;
});
var url = base_api + "api_frontend/top_products";
var response = await http.get(url);
print(response.body);
if (response.statusCode == 200) {
setState(() {
data.add(json.decode(response.body)['top_products']);
isLoading = false;
});
} else {
setState(() {
data = [];
isLoading = false;
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0.1,
backgroundColor: Colors.indigo,
title: Text('GridControll'),
//backgroundColor: Color.fromRGBO(244, 246, 249, 1),
),
body: SingleChildScrollView(
child: Column(
children: [
Container(
height: MediaQuery.of(context).size.height * 88/100,
color: Color.fromRGBO(244, 246, 249, 1),
margin: const EdgeInsets.only(
left: 0.0, bottom: 2.0, right: 0.0, top: 0),
child: getBody2(),
),
],
),
),
);
}
Widget getBody2() {
if (isLoading || data.length == 0) {
return Center(
child: CircularProgressIndicator(
valueColor: new AlwaysStoppedAnimation<Color>(primary)));
}
return StaggeredGridView.countBuilder(
padding: const EdgeInsets.all(10.0),
controller: _scrollController,
shrinkWrap: true,
// physics: NeverScrollableScrollPhysics(),
crossAxisCount: 2,
itemCount: data.length - 1,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
//builder: (context) => ProductDetails(item: data2[index]),
builder: (context) => productDetail(data[index]),
),
);
},
child: cardItem2(data[index]));
},
staggeredTileBuilder: (int index) => StaggeredTile.fit(1),
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
);
}
}
Here is grid_content.dart:
import 'package:html_unescape/html_unescape.dart';
import 'package:flutter/material.dart';
Widget cardItem2(item) {
// var img = item['thumbnail'];
// var thumbnail = base_api+"uploads/product_thumbnails/"+img;
var productId = item['product_id'];
var thumbnail = item['thumbnail'];
var unescape = new HtmlUnescape();
var name = unescape.convert(item['name']);
var unit = item['unit'];
var discount = item['discount'];
var price = item['price'];
var discountPrice = item['discount_price'];
return discount != '0%' ? Card(
elevation: 6,
shadowColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(9.0)),
child: Stack(
fit: StackFit.loose,
alignment: Alignment.center,
children: [
Column(
children: <Widget>[
Stack(
children: [
ClipRRect(
borderRadius: BorderRadius.only(topRight: Radius.circular(9), topLeft: Radius.circular(9)),
child: FadeInImage.assetNetwork(
placeholder: 'assets/loading_animated.gif',
image: thumbnail,
height: 110,
width: double.infinity,
fit: BoxFit.cover,
),
),
],
),
Padding(
padding: const EdgeInsets.only(left:6.0, right: 6.0),
child: Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name,
style: TextStyle(
fontSize: 16.0,
color: Colors.black87,
fontWeight: FontWeight.w100,
),
),
Text(
unit,
style: TextStyle(
fontSize: 12.0,
color: Colors.black45,
fontWeight: FontWeight.w100,
),
),
Row(
children: [
Expanded(
flex: 2,
child: Text(
discountPrice,
style: TextStyle(
fontSize: 16.0,
color: Colors.green,
fontWeight: FontWeight.w500,
),
),
),
Expanded(
flex: 2,
child: Text(
price,
style: TextStyle(
fontSize: 12.0,
color: Colors.black38,
fontWeight: FontWeight.w500,
decoration: TextDecoration.lineThrough,
),
),
),
ButtonTheme(
padding: EdgeInsets.symmetric(vertical: 4.0, horizontal: 6.0), //adds padding inside the button
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, //limits the touch area to the button area
minWidth: 0, //wraps child's width
height: 25,
child: FlatButton(
minWidth: 5,
height: 40,
color: Color.fromRGBO(100, 186, 2, 1),
onPressed: () {
},
child: Icon(Icons.shopping_cart, color: Colors.white,),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
side: BorderSide(color: Color.fromRGBO(100, 186, 2, 1),)),
),
),
],
),
],
),
),
),
],
),
),
],
),
],
),
) : Card(
elevation: 6,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(9.0)),
child: Stack(
fit: StackFit.loose,
alignment: Alignment.center,
children: [
Column(
children: <Widget>[
Stack(
children: [
ClipRRect(
borderRadius: BorderRadius.only(topRight: Radius.circular(9), topLeft: Radius.circular(9)),
child: FadeInImage.assetNetwork(
placeholder: 'assets/loading_animated.gif',
image: thumbnail,
height: 110,
width: double.infinity,
fit: BoxFit.cover,
),
),
],
),
Padding(
padding: const EdgeInsets.only(left:6.0, right: 6.0),
child: Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name,
style: TextStyle(
fontSize: 16.0,
color: Colors.black87,
fontWeight: FontWeight.w100,
),
),
Text(
unit,
style: TextStyle(
fontSize: 12.0,
color: Colors.black45,
fontWeight: FontWeight.w100,
),
),
Row(
children: [
Expanded(
flex: 1,
child: Text(
price,
style: TextStyle(
fontSize: 15.0,
color: Colors.green,
fontWeight: FontWeight.w500,
),
),
),
ButtonTheme(
padding: EdgeInsets.symmetric(vertical: 4.0, horizontal: 6.0),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
minWidth: 0, //wraps child's width
height: 25,
child: FlatButton(
minWidth: 10,
//height: 40,
color: Color.fromRGBO(100, 186, 2, 1),
onPressed: () {
},
child: Icon(Icons.shopping_cart, color: Colors.white,),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
side: BorderSide(color: Color.fromRGBO(100, 186, 2, 1),)),
),
),
],
),
],
),
),
),
],
),
),
],
),
],
),
);
}
productDetail(item) {
// var img = item['thumbnail'];
// var thumbnail = base_api+"uploads/product_thumbnails/"+img;
var productId = item['product_id'];
var thumbnail = item['thumbnail'];
var unescape = new HtmlUnescape();
var name = unescape.convert(item['name']);
var discount = item['discount'];
var price = item['price'];
var disPrice= item['discount_price'];
var unit = item['unit'];
return Scaffold(
appBar: AppBar(
elevation: 0.1,
iconTheme: IconThemeData(color: Colors.white),
backgroundColor: Colors.red,
title: Center(
child: Padding(
padding: const EdgeInsets.only(right: 50),
child: Text(
'Product Details',
style: TextStyle(color: Colors.white),
),
),
),
actions: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 15, right: 25.0),
child: GestureDetector(
child: Stack(
alignment: Alignment.topCenter,
children: <Widget>[
Icon(
Icons.favorite,
),
],
),
onTap: () {},
),
)
],
),
body: SingleChildScrollView(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
child: FadeInImage.assetNetwork(
placeholder: 'assets/black_circle.gif',
image: thumbnail,
height: 210,
width: 360,
fit: BoxFit.cover,
),
),
),
Center(
child: Card(
color: Colors.white38,
child: Padding(
padding: const EdgeInsets.only(left: 12.0, right: 12, top: 4, bottom: 4),
child: Text(
unit,
style: TextStyle(
fontSize: 11,
color: Colors.black87,
),
),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Center(
child: discount != '0%' ? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
disPrice,
style: TextStyle(
fontSize: 22,
color: Colors.black87,
fontWeight: FontWeight.bold),
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
price,
style: TextStyle(
fontSize: 18,
color: Colors.black54,
decoration: TextDecoration.lineThrough,
),
),
),
],
): Text(
price,
style: TextStyle(
fontSize: 22,
color: Colors.black87,
fontWeight: FontWeight.bold),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 4.0),
child: Center(
child: Text(
name,
style: TextStyle(
fontSize: 18,
color: Colors.black54,
),
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Divider(),
),
Container(
child: Center(
child: Text(
'Quantity',
style: TextStyle(color: Colors.black45, fontSize: 15),
),
),
),
Container(
child: Center(
child: Text(
'1',
style: TextStyle(
color: Colors.black,
fontSize: 22,
fontWeight: FontWeight.bold),
),
),
//child: Text(store.activeProduct.qty.toString()),
),
Padding(
padding: const EdgeInsets.only(
left: 100.0, right: 100.0, bottom: 10.0),
child: FlatButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
side: BorderSide(color: Color.fromRGBO(41, 193, 126, 1)),
),
color: Color.fromRGBO(41, 193, 126, 1),
padding: EdgeInsets.only(top: 8, bottom: 8),
child: Center(
child: Text(
'BUY NOW',
style: TextStyle(color: Colors.white, fontSize: 16),
),
),
onPressed: () {
}),
),
Padding(
padding: const EdgeInsets.only(
left: 100.0, right: 100.0, bottom: 10.0),
child: FlatButton(
padding: EdgeInsets.only(top: 8, bottom: 8),
child: Center(
child: Text(
'ADD TO CART',
style: TextStyle(color: Color.fromRGBO(41, 193, 126, 1), fontSize: 16),
),
),
onPressed: () {
}),
),
],
),
),
),
);
}
Here is the json file:
{
"top_products": [
{
"product_id": "63",
"category_id": "59",
"name": "Ice Cream",
"price": "$9",
"discount_price": "$8.91",
"discount": "1%",
"unit": "3 kg",
"thumbnail": "http://192.168.0.105/uploads/product_thumbnails/72908baa78a2db38f678283a2e483903.jpg"
},
{
"product_id": "65",
"category_id": "47",
"name": "Malta",
"price": "$5",
"discount_price": "$4.5",
"discount": "10%",
"unit": "1 kg",
"thumbnail": "http://192.168.0.105/uploads/product_thumbnails/a63dcb5e4f883eb946585d287d25c397.jpg"
},
{},
{},
{},
...
],
"message": "Top hundred products",
"status": 200,
"validity": true
}
======== Exception caught by widgets library =======================================================
The following _TypeError was thrown building:
type 'String' is not a subtype of type 'int' of 'index'
When the exception was thrown, this was the stack:
#0 cardItem2 (package:gridview_screoll/grid_content.dart:7:23)
#1 _ScrollableGridState.getBody2.<anonymous closure> (package:gridview_screoll/scroll_grid.dart:130:20)
#2 SliverChildBuilderDelegate.build (package:flutter/src/widgets/sliver.dart:449:22)
#3 SliverVariableSizeBoxAdaptorElement._build.<anonymous closure> (package:flutter_staggered_grid_view/src/widgets/sliver.dart:144:38)
#4 _HashMap.putIfAbsent (dart:collection-patch/collection_patch.dart:140:29)
...
====================================================================================================
itemCount: data.length - 1,
Change this to this:
itemCount: data.length;
What I Have are number of orders received that has be shown into a tab into a widget in flutter according with this code:
class ShipmentTab extends StatefulWidget {
#override
_ShipmentTabState createState() => _ShipmentTabState();
}
class _ShipmentTabState extends State<ShipmentTab> {
**final shipmentNumber = "16";**
#override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
color: Color(0xfffeaf0d),
child: Container(
width: 40,
height: 40,
child: Icon(
Icons.local_shipping,
color: Colors.white,
),
),
),
),
Padding(
padding: const EdgeInsets.all(13),
child: Text(
shipmentNumber,
style: TextStyle(
color: Colors.white, fontSize: 35, fontWeight: FontWeight.bold),
),
),
],
);
}
}
as you can see variable is " shipmentNumber " that show "16"
below I have listview.builder and I need to add itemCount and this count has to be refered to the tab above "16"
this is the code of the list:
Container(
height: 400,
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (ctx, int) {
return Card(
color: Color(0xFF1f2032),
elevation: 15,
child: Container(
width: 60,
height: 60,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Card(
color: Color(0xfffeaf0d),
child: Container(
height: 40,
width: 40,
child: Icon(
Icons.local_shipping,
color: Colors.white,
size: 25,
)),
),
Text(
'Ref № $int',
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
),
Text(
'Mario Rossi',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color(0xfffeaf0d),
),
),
Text(
'Consegnato',
style: TextStyle(color: Colors.lightGreenAccent),
),
Icon(
Icons.share,
color: Colors.white,
)
],
),
),
);
},
),
),
],
);
}
}
ListView.builder has itemCount parameter. I notice shipmentNumber is in String so you can parse it to int. Also you need to remove the Container height wrapping your ListView
ListView.builder(
shrinkWrap: true,
itemCount: int.parse(shipmentNumber),
itemBuilder: (BuildContext context, int index) {
/** build your Item here **/
return BuiltItem();
},
)
I am new to flutter, and working on a shopping cart project. i don't know how exatly i am suppose to ask this question but, here is what i wanted.
I am trying to update my UI when the cart item and prices changes, which means to display sum amount of products from ListView (Stateful widget) to main OrderPage Stateful widget. I know about setState() method, but i think i should use some callback methods here, dont know exactly.
I have explained in short in Image - see below img
What i have done: when user modify cart products, I have saved the value (price/product/count) in to constant value , i calculate the value and save in constant value, and later use that const var in Main widget (Main Ui), which does update when i close and reopen the page, but could not able to update when button pressed (product +/-buttons)
What i want to do is,
Update my total value when +/- buttons are pressed.
Here is my full code:
class cartConstant{
static int packageCount;
static List<int> list;
}
class OrderPage extends StatefulWidget {
#override
_OrderPageState createState() => _OrderPageState();
}
class _OrderPageState extends State<OrderPage> {
int data = 3;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
automaticallyImplyLeading: true,
iconTheme: IconThemeData(
color: Colors.black54, //change your color here
),
backgroundColor: Colors.white,
elevation: 1,
title: Text("Your order Summery",style: TextStyle(color: Colors.black54),),
centerTitle: true,
),
body: Container(
child:
FutureBuilder(
builder: (context, snapshot){
// var datas = snapshot.data;
return
ListView.builder(
physics: ClampingScrollPhysics(),
shrinkWrap: true,
itemCount: data,
itemBuilder: (BuildContext context, int index){
// Cart cart = datas[index];
return CartListView();
},
padding: EdgeInsets.symmetric(horizontal: 10.0),
scrollDirection: Axis.vertical,
);
},
),
),
bottomNavigationBar: _buildTotalContainer(),
);
}
Widget _buildTotalContainer() {
return Container(
height: 220.0,
padding: EdgeInsets.only(
left: 10.0,
right: 10.0,
),
child: Column(
children: <Widget>[
SizedBox(
height: 10.0,
),
Padding(
padding: const EdgeInsets.only(top: 10),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
"Subtotal",
style: TextStyle(
color: Color(0xFF9BA7C6),
fontSize: 16.0,
fontWeight: FontWeight.bold),
),
Text(
cartConstant.packageCount.toString(),
style: TextStyle(
color: Color(0xFF6C6D6D),
fontSize: 16.0,
fontWeight: FontWeight.bold),
),
],
),
),
SizedBox(
height: 15,
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
"Discount",
style: TextStyle(
color: Color(0xFF9BA7C6),
fontSize: 16.0,
fontWeight: FontWeight.bold),
),
Text(
"0.0",
style: TextStyle(
color: Color(0xFF6C6D6D),
fontSize: 16.0,
fontWeight: FontWeight.bold),
),
],
),
SizedBox(
height: 10.0,
),
Divider(
height: 2.0,
),
SizedBox(
height: 20.0,
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
"Cart Total",
style: TextStyle(
color: Color(0xFF9BA7C6),
fontSize: 16.0,
fontWeight: FontWeight.bold),
),
Text(
cartConstant.packageCount.toString(),
style: TextStyle(
color: Color(0xFF6C6D6D),
fontSize: 16.0,
fontWeight: FontWeight.bold),
),
],
),
SizedBox(
height: 20.0,
),
GestureDetector(
onTap: () {
// Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => SignInPage()));
},
child: Container(
height: 50.0,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(35.0),
),
child: Center(
child: Text(
"Proceed To Checkout",
style: TextStyle(
color: Colors.white,
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
),
),
),
),
SizedBox(
height: 20.0,
),
],
),
);
}
}
class CartListView extends StatefulWidget {
#override
_CartListViewState createState() => _CartListViewState();
}
class _CartListViewState extends State<CartListView> {
int _counter = 1;
int getPrice(int i,int priceC){
cartConstant.packageCount = i*priceC;
return cartConstant.packageCount;
}
#override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 15.0, vertical: 15.0),
child: Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
decoration: BoxDecoration(
border: Border.all(color: Color(0xFFD3D3D3), width: 2.0),
borderRadius: BorderRadius.circular(10.0),
),
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: 10.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
InkWell(
onTap: (){
setState(() {
_counter++;
if (_counter > 20) {
_counter = 20;
}
});
},
child: Icon(Icons.add, color: Color(0xFFD3D3D3))),
Text(
"$_counter",
style: TextStyle(fontSize: 18.0, color: Colors.grey),
),
InkWell(
onTap:(){
setState(() {
_counter--;
if (_counter < 2) {
_counter = 1;
}
});
},
child: Icon(Icons.remove, color: Color(0xFFD3D3D3))),
],
),
),
),
SizedBox(
width: 20.0,
),
Container(
height: 70.0,
width: 70.0,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/food.jpg"),
fit: BoxFit.cover),
borderRadius: BorderRadius.circular(35.0),
boxShadow: [
BoxShadow(
color: Colors.black54,
blurRadius: 5.0,
offset: Offset(0.0, 2.0))
]),
),
SizedBox(
width: 20.0,
),
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Employee Package",
style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold),
),
SizedBox(height: 5.0),
SizedBox(height: 5.0),
Container(
height: 25.0,
width: 120.0,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
Row(
children: <Widget>[
Text("Price",
style: TextStyle(
color: Color(0xFFD3D3D3),
fontWeight: FontWeight.bold)),
SizedBox(
width: 5.0,
),
InkWell(
onTap: () {},
child: Text(
getPrice(_counter, 2000).toString(),
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.red,
),
),
),
SizedBox(
width: 10.0,
),
],
),
],
),
),
],
),
Spacer(),
GestureDetector(
onTap: () {
},
child: Icon(
Icons.cancel,
color: Colors.grey,
),
),
],
),
),
);
}
}
you can also check from my cart screen shot below:
You can copy paste run full code below
You can use callback refresh() and pass callback to CartListView
code snippet
class _OrderPageState extends State<OrderPage> {
int data = 3;
void refresh() {
setState(() {});
}
...
itemBuilder: (BuildContext context, int index) {
// Cart cart = datas[index];
return CartListView(refresh);
},
...
class CartListView extends StatefulWidget {
VoidCallback callback;
CartListView(this.callback);
...
InkWell(
onTap: () {
setState(() {
_counter++;
if (_counter > 20) {
_counter = 20;
}
});
widget.callback();
},
working demo
full code
import 'package:flutter/material.dart';
class cartConstant {
static int packageCount;
static List<int> list;
}
class OrderPage extends StatefulWidget {
#override
_OrderPageState createState() => _OrderPageState();
}
class _OrderPageState extends State<OrderPage> {
int data = 3;
void refresh() {
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
automaticallyImplyLeading: true,
iconTheme: IconThemeData(
color: Colors.black54, //change your color here
),
backgroundColor: Colors.white,
elevation: 1,
title: Text(
"Your order Summery",
style: TextStyle(color: Colors.black54),
),
centerTitle: true,
),
body: Container(
child: FutureBuilder(
builder: (context, snapshot) {
// var datas = snapshot.data;
return ListView.builder(
physics: ClampingScrollPhysics(),
shrinkWrap: true,
itemCount: data,
itemBuilder: (BuildContext context, int index) {
// Cart cart = datas[index];
return CartListView(refresh);
},
padding: EdgeInsets.symmetric(horizontal: 10.0),
scrollDirection: Axis.vertical,
);
},
),
),
bottomNavigationBar: _buildTotalContainer(),
);
}
Widget _buildTotalContainer() {
return Container(
height: 220.0,
padding: EdgeInsets.only(
left: 10.0,
right: 10.0,
),
child: Column(
children: <Widget>[
SizedBox(
height: 10.0,
),
Padding(
padding: const EdgeInsets.only(top: 10),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
"Subtotal",
style: TextStyle(
color: Color(0xFF9BA7C6),
fontSize: 16.0,
fontWeight: FontWeight.bold),
),
Text(
cartConstant.packageCount.toString(),
style: TextStyle(
color: Color(0xFF6C6D6D),
fontSize: 16.0,
fontWeight: FontWeight.bold),
),
],
),
),
SizedBox(
height: 15,
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
"Discount",
style: TextStyle(
color: Color(0xFF9BA7C6),
fontSize: 16.0,
fontWeight: FontWeight.bold),
),
Text(
"0.0",
style: TextStyle(
color: Color(0xFF6C6D6D),
fontSize: 16.0,
fontWeight: FontWeight.bold),
),
],
),
SizedBox(
height: 10.0,
),
Divider(
height: 2.0,
),
SizedBox(
height: 20.0,
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
"Cart Total",
style: TextStyle(
color: Color(0xFF9BA7C6),
fontSize: 16.0,
fontWeight: FontWeight.bold),
),
Text(
"8000",
style: TextStyle(
color: Color(0xFF6C6D6D),
fontSize: 16.0,
fontWeight: FontWeight.bold),
),
],
),
SizedBox(
height: 20.0,
),
GestureDetector(
onTap: () {
// Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => SignInPage()));
},
child: Container(
height: 50.0,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(35.0),
),
child: Center(
child: Text(
"Proceed To Checkout",
style: TextStyle(
color: Colors.white,
fontSize: 18.0,
fontWeight: FontWeight.bold,
),
),
),
),
),
SizedBox(
height: 20.0,
),
],
),
);
}
}
class CartListView extends StatefulWidget {
VoidCallback callback;
CartListView(this.callback);
#override
_CartListViewState createState() => _CartListViewState();
}
class _CartListViewState extends State<CartListView> {
int _counter = 1;
int getPrice(int i, int priceC) {
cartConstant.packageCount = i * priceC;
return cartConstant.packageCount;
}
#override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 15.0, vertical: 15.0),
child: Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
decoration: BoxDecoration(
border: Border.all(color: Color(0xFFD3D3D3), width: 2.0),
borderRadius: BorderRadius.circular(10.0),
),
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: 10.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
InkWell(
onTap: () {
setState(() {
_counter++;
if (_counter > 20) {
_counter = 20;
}
});
widget.callback();
},
child: Icon(Icons.add, color: Color(0xFFD3D3D3))),
Text(
"$_counter",
style: TextStyle(fontSize: 18.0, color: Colors.grey),
),
InkWell(
onTap: () {
setState(() {
_counter--;
if (_counter < 2) {
_counter = 1;
}
});
widget.callback();
},
child: Icon(Icons.remove, color: Color(0xFFD3D3D3))),
],
),
),
),
SizedBox(
width: 20.0,
),
Container(
height: 70.0,
width: 70.0,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/food.jpg"),
fit: BoxFit.cover),
borderRadius: BorderRadius.circular(35.0),
boxShadow: [
BoxShadow(
color: Colors.black54,
blurRadius: 5.0,
offset: Offset(0.0, 2.0))
]),
),
SizedBox(
width: 20.0,
),
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Employee Package",
style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold),
),
SizedBox(height: 5.0),
SizedBox(height: 5.0),
Container(
height: 25.0,
width: 120.0,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
Row(
children: <Widget>[
Text("Price",
style: TextStyle(
color: Color(0xFFD3D3D3),
fontWeight: FontWeight.bold)),
SizedBox(
width: 5.0,
),
InkWell(
onTap: () {},
child: Text(
getPrice(_counter, 2000).toString(),
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.red,
),
),
),
SizedBox(
width: 10.0,
),
],
),
],
),
),
],
),
Spacer(),
GestureDetector(
onTap: () {},
child: Icon(
Icons.cancel,
color: Colors.grey,
),
),
],
),
),
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: OrderPage(),
);
}
}
When the button is tapped, you just need to update the Subtotal amount and cart total.
Step 1 : Replace the harcoded value by a variable. So, something like :
Row(
children: <Widget>[
Text(
"Subtotal",
style: ...
),
Text(
"$subTotal",
style: ....
),
],
),
Step 2 : Now, add a code to calcualte subTotal and cartTotal. You already have code which increments and decrements the variable _counter. You just need to tweak that part like :
setState( (){
_counter++;
// So, the quantity is increased. Just get the price of current item and add in the sub total.
subTotal += priceC;
cartTotal = subTotal - discount;
} );