How to read Json from file and use it in this case - flutter

I am an absolute beginner in Flutter and want to build a timetable app. I don't get how I can use a local JSON file (including using Future if needed) to use it as data for the ListView (seperated).
I want to get the data of the lessons from the JSON file to display them in the app. Room, Time and teacher for every lesson.
Showing me how to implement it into my code would be great!
Any help and tip is much appreciated.
My code:
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:flutter/services.dart';
import 'dart:async' show Future;
final List<String> entries = <String>['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'];
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: "Stundenplan",
home: DefaultTabController(
length: 5,
child: Scaffold(
appBar: AppBar(
bottom: const TabBar(
tabs: [
Tab(text: "Mo"),
Tab(text: "Di"),
Tab(text: "Mi"),
Tab(text: "Do"),
Tab(text: "Fr"),
],
),
title: const Text('Stundenplan'),
backgroundColor: Colors.blue,
),
body: TabBarView(
children: [
// MONDAY
Center(
child: ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: mondayLessons.length,
itemBuilder: (BuildContext context, int index) {
return Container(
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(15)),
color: Colors.red,
),
alignment: Alignment.center,
height: 150,
child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
/*2*/
Container(
padding: const EdgeInsets.only(top: 0),
alignment: Alignment.topCenter,
child: Text(
'${index + 1} - ${jsonData["Montag"]}',
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 20,
),
),
),
Container(
padding: const EdgeInsets.only(top: 0),
alignment: Alignment.topCenter,
child: Text(
times[index],
style: const TextStyle(
color: Colors.black,
fontSize: 17.5,
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
mondayTeacher[index],
style: const TextStyle(
color: Colors.black,
fontSize: 17.5,
),
),
Text(
mondayRooms[index],
style: const TextStyle(
color: Colors.black,
fontSize: 17.5,
),
),]
),
],
),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
),
),
// TUESDAY
Center(
child: ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: tuesdayLessons.length,
itemBuilder: (BuildContext context, int index) {
return Container(
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(15)),
color: Colors.green,
),
alignment: Alignment.center,
height: 150,
child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
/*2*/
Container(
padding: const EdgeInsets.only(top: 0),
alignment: Alignment.topCenter,
child: Text(
'${index + 1} - ${tuesdayLessons[index]}',
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 20,
),
),
),
Container(
padding: const EdgeInsets.only(top: 0),
alignment: Alignment.topCenter,
child: Text(
'${times[index]} Uhr',
style: const TextStyle(
color: Colors.black,
fontSize: 17.5,
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
tuesdayTeacher[index],
style: const TextStyle(
color: Colors.black,
fontSize: 17.5,
),
),
Text(
tuesdayRooms[index],
style: const TextStyle(
color: Colors.black,
fontSize: 17.5,
),
),]
),
],
),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
),
),
// WEDNESDAY
Center(
child: ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: wednesdayLessons.length,
itemBuilder: (BuildContext context, int index) {
return Container(
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(15)),
color: Colors.yellow,
),
alignment: Alignment.center,
height: 150,
child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
/*2*/
Container(
padding: const EdgeInsets.only(top: 0),
alignment: Alignment.topCenter,
child: Text(
'${index + 1} - ${wednesdayLessons[index]}',
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 20,
),
),
),
Container(
padding: const EdgeInsets.only(top: 0),
alignment: Alignment.topCenter,
child: Text(
times[index],
style: const TextStyle(
color: Colors.black,
fontSize: 17.5,
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
wednesdayTeacher[index],
style: const TextStyle(
color: Colors.black,
fontSize: 17.5,
),
),
Text(
wednesdayRooms[index],
style: const TextStyle(
color: Colors.black,
fontSize: 17.5,
),
),]
),
],
),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
),
),
// THURSDAY
Center(
child: ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: thursdayLessons.length,
itemBuilder: (BuildContext context, int index) {
return Container(
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(15)),
color: Colors.red,
),
alignment: Alignment.center,
height: 150,
child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
/*2*/
Container(
padding: const EdgeInsets.only(top: 0),
alignment: Alignment.topCenter,
child: Text(
'${index + 1} - ${thursdayLessons[index]}',
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 20,
),
),
),
Container(
padding: const EdgeInsets.only(top: 0),
alignment: Alignment.topCenter,
child: Text(
'${times[index]} Uhr',
style: const TextStyle(
color: Colors.black,
fontSize: 17.5,
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
thursdayTeacher[index],
style: const TextStyle(
color: Colors.black,
fontSize: 17.5,
),
),
Text(
thursdayRooms[index],
style: const TextStyle(
color: Colors.black,
fontSize: 17.5,
),
),]
),
],
),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
),
),
//FRIDAY
Center(
child: ListView.separated(
padding: const EdgeInsets.all(8),
itemCount: fridayLessons.length,
itemBuilder: (BuildContext context, int index) {
return Container(
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(15)),
color: Colors.green,
),
alignment: Alignment.center,
height: 150,
child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
/*2*/
Container(
padding: const EdgeInsets.only(top: 0),
alignment: Alignment.topCenter,
child: Text(
'${index + 1} - ${fridayLessons[index]}',
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 20,
),
),
),
Container(
padding: const EdgeInsets.only(top: 0),
alignment: Alignment.topCenter,
child: Text(
'${times[index]} Uhr',
style: const TextStyle(
color: Colors.black,
fontSize: 17.5,
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
fridayTeacher[index],
style: const TextStyle(
color: Colors.black,
fontSize: 17.5,
),
),
Text(
fridayRooms[index],
style: const TextStyle(
color: Colors.black,
fontSize: 17.5,
),
),]
),
],
),
);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
),
),
],
),
),
),
);
}
}

Keep the json file into your assets folder, then follow the below code:
String? data = await DefaultAssetBundle.of(context).loadString("assets/someData.json");
val jsonResult = jsonDecode(someData);
This code will be used to load json from the asset

Adding to this answer by Gourango, you can copy paste your json in https://app.quicktype.io/ , it will generate the classes you need to handle json more easily.

I am using this in my current project:
// load JSON
final String response =
await rootBundle.loadString('lib/assets/file.json');
final data = await json.decode(response);

Related

listview shows on emulator but not on actual phone

as typed above i am trying to display information using a listview but i noticed whenever i port this app to my phone via APK it just shows the background color nothing else! maybe im using expanded wrong or something i have no clue. this app works as intended on my emulator, the emulator im using is pixel 4 api 30
code home_page.dart
class _SummonerProfileRouteState extends State<SummonerProfileRoute> {
List<SummonerRank> SummonerRankList = <SummonerRank>[];
void getSummonerRankfromApi() async {
SummonerRankApi.getSummonerRank(summonerId).then((response) {
setState(() {
Iterable list = json.decode(response.body);
SummonerRankList =
list.map((model) => SummonerRank.fromJson(model)).toList();
});
});
}
String summonerName, summonerId;
int profileIconId, summonerLevel;
_SummonerProfileRouteState(this.summonerName, this.summonerId,
this.profileIconId, this.summonerLevel);
#override
void initState() {
super.initState();
getSummonerRankfromApi();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: customAppBar(),
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [
bgColorFront,
bgColorEnd,
],
),
),
child: ListView(
children: [
Expanded(
child: Column(
children: [
Padding(padding: EdgeInsets.only(top: 20)),
Text(
summonerName,
style: TextStyle(
fontSize: 35,
fontFamily: 'Spiegel',
fontWeight: FontWeight.bold,
),
),
Text(
"Level ${summonerLevel.toString()}",
style: TextStyle(
fontSize: 20,
color: customColorTextBlue,
),
),
Padding(padding: EdgeInsets.only(top: 10)),
Container(
width: 200,
height: 200,
child: AspectRatio(
aspectRatio: 1 / 1,
child: ClipOval(
child: FadeInImage.assetNetwork(
fit: BoxFit.cover,
placeholder: "images/placeholder.jpg",
image:
"https://ddragon.leagueoflegends.com/cdn/12.22.1/img/profileicon/$profileIconId.png"),
),
),
),
ListView(
shrinkWrap: true,
children: [
GridView.builder(
shrinkWrap: true,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
mainAxisSpacing: 20,
crossAxisSpacing: 20,
crossAxisCount: 2),
itemCount: SummonerRankList.length,
itemBuilder: (BuildContext ctx, index) {
return ListTile(
title: Text(
modeChecker(
SummonerRankList[index].queueType),
style: TextStyle(
fontFamily: 'Spiegel',
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"${SummonerRankList[index].tier} ${SummonerRankList[index].rank}",
style: TextStyle(
color: customColorTextBlue,
fontSize: 18,
),
),
Text(
"${SummonerRankList[index].leaguePoints} LP",
style: TextStyle(
color: customColorTextBlue,
fontSize: 18,
),
),
Text(
"${calculateWinrate(SummonerRankList[index].wins, SummonerRankList[index].losses)}% Winrate",
style: TextStyle(
color: customColorTextBlue,
fontSize: 16,
),
),
],
));
}),
],
),
Container(
width: double.maxFinite,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
MyElevatedButton(
width: 350,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => AllChampionsListedRoute(summonerId, summonerName)));
},
borderRadius: BorderRadius.circular(20),
child: Row(
children: [
Spacer(),
Icon(
Icons.call_made_sharp,
color: customColorTextBlue,
size: 26,
),
Padding(padding: EdgeInsets.only(right: 5)),
Text(
'Check champion statistics',
style: TextStyle(
color: customColorTextBlue,
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
Spacer(),
],
),
),
],
),
),
],
),
),
],
),
));
}
}
Replace ListView with Column widget. You cant use Expanded inside ListView
return Scaffold(
appBar: customAppBar(),
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [
bgColorFront,
bgColorEnd,
],
),
),
child: Column( //this
children: [
Expanded(
child: Column(

Flutter comment_tree 0.3.0 How to remove replies under comments

I use the component as in the description, I can’t figure out how to remove the answer (child component) in the component itself, or at least how to check if it exists, then show it, if not, then don’t show it.
https://gist.github.com/lomanu4/3abba49f6fbcecbde4c07df82c3ce11c
class _ComentCardState extends State<ComentCard> {
bool childcomment = false;
#override
Widget build(BuildContext context) {
return Column(children: [
Container(
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
child: CommentTreeWidget<Comment, Comment?>(
Comment(
avatar: 'null',
userName: widget.snap['name'],
content: '${widget.snap['text']} '),
[
Comment(avatar: 'null', userName: 'null', content: 'null'),
],
treeThemeData: childcomment
? TreeThemeData(lineColor: Colors.green[500]!, lineWidth: 3)
: TreeThemeData(lineColor: Colors.green[500]!, lineWidth: 3),
avatarRoot: (context, data) => PreferredSize(
preferredSize: const Size.fromRadius(18),
child: Row(
children: [
CircleAvatar(
radius: 18,
backgroundColor: Colors.grey,
backgroundImage:
NetworkImage(widget.snap['profilePic'].toString()),
),
],
),
),
avatarChild: (context, data) => const PreferredSize(
preferredSize: Size.fromRadius(12),
child: CircleAvatar(
radius: 12,
backgroundColor: Colors.grey,
backgroundImage: AssetImage('lib/assets/homescreen.png'),
),
),
contentChild: (context, data) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding:
const EdgeInsets.symmetric(vertical: 8, horizontal: 8),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'dangngocduc',
style: Theme.of(context).textTheme.caption?.copyWith(
fontWeight: FontWeight.w600, color: Colors.black),
),
const SizedBox(
height: 4,
),
Text(
'${data!.content}',
style: Theme.of(context).textTheme.caption?.copyWith(
fontWeight: FontWeight.w300, color: Colors.black),
),
],
),
),
DefaultTextStyle(
style: Theme.of(context).textTheme.caption!.copyWith(
color: Colors.grey[700], fontWeight: FontWeight.bold),
child: Padding(
padding: const EdgeInsets.only(top: 4),
child: Row(
children: const [
SizedBox(
width: 8,
),
Text('Reply'),
],
),
),
)
],
);
},
contentRoot: (context, data) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding:
const EdgeInsets.symmetric(vertical: 8, horizontal: 8),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(12)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.snap['name'],
style: Theme.of(context).textTheme.caption!.copyWith(
fontWeight: FontWeight.w600, color: Colors.black),
),
const SizedBox(
height: 4,
),
Text(
'${data.content}',
style: Theme.of(context).textTheme.caption!.copyWith(
fontWeight: FontWeight.w300, color: Colors.black),
),
const SizedBox(
height: 4,
),
],
),
),
DefaultTextStyle(
style: Theme.of(context).textTheme.caption!.copyWith(
color: Colors.grey[700], fontWeight: FontWeight.bold),
child: Padding(
padding: const EdgeInsets.only(top: 4),
child: Row(
children: [
SizedBox(
width: 8,
),
Text('Like'),
SizedBox(
width: 24,
),
Expanded(child: Text('Reply')),
Container(
padding: const EdgeInsets.all(8),
child: const Icon(
Icons.favorite_border,
size: 16,
),
)
],
),
),
),
],
);
},
),
),
]);
}

Bottom Overflowed by 81 Pixels

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.

SliverPersistentHeaderDelegate not fully collapsed

I'm having a hard time making a custom collapsing toolbar, attached below is a video for a normal case.
Then here's a screen record of the misbehavior, most of the time this happens.
Aside from the fact that the scrolling is not so snappy, you'll see in the second video that the sliver on the top is not completely collapsed.
Do you have any suggestion to improve the performance of the app and a solution for the bug?
here's my code inside the SliverPersistentHeaderDelegate
class DashboardHeaderPersistentDelegate extends SliverPersistentHeaderDelegate {
...
#override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
double shrinkPercentage = min(1, shrinkOffset / (maxExtent - minExtent));
double titleTopMargin = titleCollapsedTopPadding +
(titleExpandedTopPadding - titleCollapsedTopPadding) *
(1 - shrinkPercentage);
double titleFontSize = titleCollapsedFontSize +
(titleExpandedFontSize - titleCollapsedFontSize) *
(1 - shrinkPercentage);
double infoWidgetHeight = minExtent +
(maxExtent - minExtent) -
shrinkOffset -
titleTopMargin -
titleFontSize -
44;
double collapasedInfoOpacity = max(0, shrinkPercentage-.7)/.3;
return Material(
elevation: 0,
shadowColor: Colors.white,
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
height: titleFontSize,
alignment: Alignment.center,
child: Text(
'\$ 5329.05',
style: TextStyle(
fontFamily: 'Barlow',
fontSize: titleFontSize,
fontWeight: FontWeight.w500),
),
margin: EdgeInsets.only(top: titleTopMargin, bottom: 8),
),
Container(
height: shrinkPercentage == 1 ? 20 : infoWidgetHeight,
width: MediaQuery.of(context).size.width,
alignment: Alignment.center,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
Opacity(
opacity: 1 - shrinkPercentage,
child: _buildInformationWidget(context),
),
Opacity(
opacity: collapasedInfoOpacity,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: _buildCollapsedInformationWidget(),
),
)
],
),
)
],
),
),
);
}
Widget _buildInformationWidget(BuildContext context) => ClipRect(
child: OverflowBox(
maxWidth: double.infinity,
maxHeight: double.infinity,
child: FittedBox(
fit: BoxFit.fitWidth,
alignment: Alignment.center,
child: Container(
width: MediaQuery.of(context).size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'AVAILABLE BALANCE',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w900,
color: Colors.black26),
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
width: 100,
child: Text(
'\$ 11200',
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: 'Barlow',
fontSize: 18,
fontWeight: FontWeight.w700,
color: Colors.green[400]),
),
),
Text(
' I ',
style: TextStyle(fontSize: 20, color: Colors.black12),
),
Container(
width: 100,
child: Text(
'\$ 400',
style: TextStyle(
fontFamily: 'Barlow',
fontSize: 18,
fontWeight: FontWeight.w700,
color: Colors.red[400]),
),
)
],
),
),
Container(
margin: EdgeInsets.only(left: 12, top: 12),
alignment: Alignment.centerLeft,
child: Text(
"CATEGORIES",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w900,
color: Colors.black26),
),
),
Container(
height: 88,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: categories.length,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.only(
left: (index == 0) ? 24.0 : 8.0,
right: (index == categories.length - 1)
? 24.0
: 8.0),
child: _buildCategoryItem(
categoriesIcons[index], categories[index], .9),
);
}),
)
],
),
),
),
),
);
Widget _buildCollapsedInformationWidget() => Row(
children: [
Text("Recent"),
Spacer(),
Container(
child: Text(
'\$ 11200',
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: 'Barlow',
fontSize: 14,
fontWeight: FontWeight.w700,
color: Colors.green[400]),
),
),
Text(
' I ',
style: TextStyle(fontSize: 20, color: Colors.black12),
),
Container(
child: Text(
'\$ 400',
style: TextStyle(
fontFamily: 'Barlow',
fontSize: 14,
fontWeight: FontWeight.w700,
color: Colors.red[400]),
),
)
],
);
Widget _buildCategoryItem(
IconData data, String categoryTitle, double percentage) =>
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Stack(
alignment: Alignment.center,
children: <Widget>[
Container(
decoration: BoxDecoration(
border: Border.all(width: 1, color: Colors.black12),
borderRadius: BorderRadius.circular(28),
color: Colors.blue[400]),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Icon(
data,
size: 28,
color: Colors.white,
),
),
),
Container(
width: 40,
height: 40,
child: CircularProgressIndicator(
value: percentage,
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation(Colors.white),
),
)
],
),
Container(
width: 72,
alignment: Alignment.center,
child: Text(categoryTitle,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
maxLines: 1,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Colors.black45)),
)
],
);
...
}
When it's possible..Use dependend on parent size widgets insted of calcualting children sizes manualy.
FittedBox. Can scale the font size of the children widget according on parents size and fit parameter.
ConstrainedBox, BoxConstraints.tightFor
Expanded. Probably you know how it works.
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: SafeArea(
child: MyHomePage(),
),
),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
SliverPersistentHeader(
pinned: true,
floating: false,
delegate: DashboardHeaderPersistentDelegate(),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(_, i) => Card(
margin: const EdgeInsets.all(10),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Expanded(
flex: 1,
child: Text(
i.toString(),
),
),
const Expanded(
flex: 3,
child: Text('Text'),
),
],
),
),
),
childCount: 100,
),
),
],
);
}
}
const categories = [
'Grocieries',
'Transport',
'House Rent',
'Shopping',
'Career'
];
const categoriesIcons = [
Icons.ac_unit,
Icons.access_alarms,
Icons.dashboard,
Icons.accessible_forward,
Icons.backspace,
];
class DashboardHeaderPersistentDelegate extends SliverPersistentHeaderDelegate {
#override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
double shrinkPercentage = min(1, shrinkOffset / (maxExtent - minExtent));
return Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.blueAccent,
),
),
child: Material(
elevation: 0,
shadowColor: Colors.white,
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
ConstrainedBox(
constraints: BoxConstraints.tightFor(
height: max(
60,
100 * (1 - shrinkPercentage),
),
),
child: FittedBox(
child: Container(
padding: EdgeInsets.all(20),
width: 200,
child: const Text(
'\$ 5329.05',
style: TextStyle(
fontFamily: 'Barlow',
fontSize: 30,
fontWeight: FontWeight.w500,
),
),
),
),
),
Expanded(
child: Stack(
alignment: Alignment.bottomCenter,
children: [
if (shrinkPercentage != 1)
Opacity(
opacity: 1 - shrinkPercentage,
child: _buildInformationWidget(context),
),
if (shrinkPercentage != 0)
Opacity(
opacity: shrinkPercentage,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: _buildCollapsedInformationWidget(),
),
),
],
),
)
],
),
),
),
);
}
Widget _buildInformationWidget(BuildContext context) => ClipRect(
child: OverflowBox(
maxWidth: double.infinity,
maxHeight: double.infinity,
child: FittedBox(
fit: BoxFit.fitWidth,
alignment: Alignment.center,
child: Container(
width: MediaQuery.of(context).size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
const Text(
'AVAILABLE BALANCE',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w900,
color: Colors.black26),
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
width: 100,
child: Text(
'\$ 11200',
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: 'Barlow',
fontSize: 18,
fontWeight: FontWeight.w700,
color: Colors.green[400],
),
),
),
const Text(
' I ',
style: TextStyle(
fontSize: 20,
color: Colors.black12,
),
),
Container(
width: 100,
child: Text(
'\$ 400',
style: TextStyle(
fontFamily: 'Barlow',
fontSize: 18,
fontWeight: FontWeight.w700,
color: Colors.red[400],
),
),
)
],
),
),
Container(
margin: EdgeInsets.only(left: 12, top: 12),
alignment: Alignment.centerLeft,
child: const Text(
"CATEGORIES",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w900,
color: Colors.black26,
),
),
),
Container(
height: 88,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: categories.length,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.only(
left: (index == 0) ? 24.0 : 8.0,
right: (index == categories.length - 1)
? 24.0
: 8.0),
child: _buildCategoryItem(
categoriesIcons[index],
categories[index],
.9,
),
);
},
),
)
],
),
),
),
),
);
Widget _buildCollapsedInformationWidget() => Row(
children: [
const Text("Recent"),
const Spacer(),
Container(
child: Text(
'\$ 11200',
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: 'Barlow',
fontSize: 14,
fontWeight: FontWeight.w700,
color: Colors.green[400],
),
),
),
const Text(
' I ',
style: TextStyle(
fontSize: 20,
color: Colors.black12,
),
),
Container(
child: Text(
'\$ 400',
style: TextStyle(
fontFamily: 'Barlow',
fontSize: 14,
fontWeight: FontWeight.w700,
color: Colors.red[400],
),
),
)
],
);
Widget _buildCategoryItem(
IconData data, String categoryTitle, double percentage) =>
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Stack(
alignment: Alignment.center,
children: <Widget>[
Container(
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Colors.black12,
),
borderRadius: BorderRadius.circular(28),
color: Colors.blue[400],
),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Icon(
data,
size: 28,
color: Colors.white,
),
),
),
Container(
width: 40,
height: 40,
child: CircularProgressIndicator(
value: percentage,
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation(Colors.white),
),
)
],
),
Container(
width: 72,
alignment: Alignment.center,
child: Text(
categoryTitle,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
maxLines: 1,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Colors.black45,
),
),
)
],
);
#override
double get maxExtent => 300;
#override
double get minExtent => 80;
#override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
}

Flutter: Updating UI from outside of a StatefulWidget

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;
} );