how to make this table scrollable to bottom - flutter

i am beginner in flutter , i wrote a code with a leagueboard table from api , after i executed i found that my table is not scrolling , the scroll appears only on the top but no scrolling to bottom
here what i have tried:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:http/http.dart' as http;
class LeagueBoard extends StatefulWidget {
#override
_LeagueBoardState createState() => _LeagueBoardState();
}
class _LeagueBoardState extends State<LeagueBoard> {
List<Club> clubs = [];
getTable() async {
http.Response response = await http.get(
'http://api.football-data.org/v2/competitions/PL/standings',
headers: {'X-Auth-Token': '86014f6025ae430dba078acc94bb2647'});
String body = response.body;
Map data = jsonDecode(body);
List table = data['standings'][0]['table'];
// for (var team in table) {
// clubs.add(Club(team['team']['crestUrl'].toString(), team['position'].toString(),team['points'].toString(),team['points'].toString(),team['playedGames'].toString(),team['won'].toString(),
// team['draw'].toString(),team['lost'].toString(),team['goalsFor'],team['goalsAgainst']));
// print(team);
// }
// for (var team in table) {
// clubs.add(Club(team['team']['crestUrl'].toString(), team['position'].toString(),team['points'].toString(),team['points'].toString(),team['playedGames'].toString(),team['won'].toString(),
// team['draw'].toString(),team['lost'].toString(),team['goalsFor'],team['goalsAgainst']));
// print(team);
// }
// for (var team in clubs) {
// debugPrint(team.toString());
// }
setState(() {
for (var team in table) {
clubs.add(Club(team['team']['name'],team['team']['crestUrl'], team['position'].toString(),team['points'].toString(),team['playedGames'].toString(),team['won'].toString(),
team['draw'].toString(),team['lost'].toString(),team['goalsFor'],team['goalsAgainst']));
print("hello");
}
});
}
// List<Club> clubs = [ Club("Manchester City","https://upload.wikimedia.org/wikipedia/fr/thumb/b/ba/Logo_Manchester_City_2016.svg/1200px-Logo_Manchester_City_2016.svg.png","1","77","17","15","1","1",25,5),
// Club("Chelsea","https://upload.wikimedia.org/wikipedia/fr/thumb/5/51/Logo_Chelsea.svg/768px-Logo_Chelsea.svg.png","2","70","17","13","2","3",19,8),
// Club("Manchester City","https://upload.wikimedia.org/wikipedia/fr/thumb/b/ba/Logo_Manchester_City_2016.svg/1200px-Logo_Manchester_City_2016.svg.png","1","77","17","15","1","1",25,5),
// Club("Chelsea","https://upload.wikimedia.org/wikipedia/fr/thumb/5/51/Logo_Chelsea.svg/768px-Logo_Chelsea.svg.png","2","70","17","13","2","3",19,8),
// Club("Manchester City","https://upload.wikimedia.org/wikipedia/fr/thumb/b/ba/Logo_Manchester_City_2016.svg/1200px-Logo_Manchester_City_2016.svg.png","1","77","17","15","1","1",25,5),
// Club("Chelsea","https://upload.wikimedia.org/wikipedia/fr/thumb/5/51/Logo_Chelsea.svg/768px-Logo_Chelsea.svg.png","2","70","17","13","2","3",19,8),
// Club("Manchester City","https://upload.wikimedia.org/wikipedia/fr/thumb/b/ba/Logo_Manchester_City_2016.svg/1200px-Logo_Manchester_City_2016.svg.png","1","77","17","15","1","1",25,5),
// Club("Chelsea","https://upload.wikimedia.org/wikipedia/fr/thumb/5/51/Logo_Chelsea.svg/768px-Logo_Chelsea.svg.png","2","70","17","13","2","3",19,8),
// Club("Manchester City","https://upload.wikimedia.org/wikipedia/fr/thumb/b/ba/Logo_Manchester_City_2016.svg/1200px-Logo_Manchester_City_2016.svg.png","1","77","17","15","1","1",25,5),
// Club("Chelsea","https://upload.wikimedia.org/wikipedia/fr/thumb/5/51/Logo_Chelsea.svg/768px-Logo_Chelsea.svg.png","2","70","17","13","2","3",19,8),
// Club("Manchester City","https://upload.wikimedia.org/wikipedia/fr/thumb/b/ba/Logo_Manchester_City_2016.svg/1200px-Logo_Manchester_City_2016.svg.png","1","77","17","15","1","1",25,5),
// Club("Chelsea","https://upload.wikimedia.org/wikipedia/fr/thumb/5/51/Logo_Chelsea.svg/768px-Logo_Chelsea.svg.png","2","70","17","13","2","3",19,8),
// Club("Manchester City","https://upload.wikimedia.org/wikipedia/fr/thumb/b/ba/Logo_Manchester_City_2016.svg/1200px-Logo_Manchester_City_2016.svg.png","1","77","17","15","1","1",25,5),
// Club("Chelsea","https://upload.wikimedia.org/wikipedia/fr/thumb/5/51/Logo_Chelsea.svg/768px-Logo_Chelsea.svg.png","2","70","17","13","2","3",19,8),];
#override
void initState() {
super.initState();
getTable();
}
#override
Widget build(BuildContext context) {
return clubs == null
? Container(
color: Colors.white,
child: Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
Color(0xFFe70066),
),
),
),
)
: Scaffold(
appBar: AppBar(
title: Text("LeagueBoard"),
backgroundColor: Colors.blue[300],
elevation: 0.0,
),
body: SingleChildScrollView(
child: Column(
children: [
TopRow(),
ListView.builder(
shrinkWrap: true,
// physics: NeverScrollableScrollPhysics(),
itemCount: clubs.length,
itemBuilder: (context, index) {
return TableRow(index: index, clubs:clubs);
},
),
],
),
),
);
}
}
class TopRow extends StatelessWidget {
const TopRow({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
TextStyle textStyle = TextStyle(fontSize: 11, fontWeight: FontWeight.bold);
TextStyle textStyle2 = TextStyle(fontSize: 13);
return Container(
child: Row(
children: [
Container(
alignment: Alignment.center,
width: 30,
height: 30,
child: Text('#'),
),
SizedBox(width: 20),
Container(alignment: Alignment.center, child: Text('Team')),
Spacer(),
Container(
width: 28,
child: Text('MP', style: textStyle),
),
SizedBox(
width: 5,
),
Container(
width: 28,
child: Text('W', style: textStyle),
),
SizedBox(
width: 5,
),
Container(
width: 28,
child: Text('D', style: textStyle),
),
SizedBox(
width: 5,
),
Container(
width: 28,
child: Text('L', style: textStyle),
),
SizedBox(
width: 5,
),
Container(
width: 28,
child: Text('GD', style: textStyle),
),
SizedBox(
width: 5,
),
Container(
width: 28,
child: Text('Pts', style: textStyle),
),
SizedBox(
width: 5,
),
Container(
width: 5,
height: 20,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.grey[800],
),
padding: EdgeInsets.fromLTRB(10, 5, 2, 5),
),
],
),
);
}
}
class TableRow extends StatelessWidget {
final int index;
final List<Club> clubs;
const TableRow({
this.index,
this.clubs,
Key key,
}) : super(key: key);
/////////////////////////////////////////////////////////////////////linkwell
////////////////////////////////////////////////////////////////////
#override
Widget build(BuildContext context) {
TextStyle textStyle = TextStyle(fontSize: 11, fontWeight: FontWeight.bold);
TextStyle textStyle2 = TextStyle(fontSize: 13, fontWeight: FontWeight.bold);
return Container(
width: double.infinity,
height: 40,
decoration: BoxDecoration(
border: Border.all(color: Colors.black38, width: 0.2),
color: index == 0 ? Colors.yellow[100] : Colors.purpleAccent[20],
),
child: Row(
children: [
Container(//iinkwell
alignment: Alignment.center,
width: 30,
height: 40,
color: index < 2
? Colors.blue
: index == 2
? Colors.red[400]
: index > 11
? Colors.red[800]
: Colors.grey[700],
child: Text(
(index + 1).toString(),
style: TextStyle(color: Colors.white),
),
),
SizedBox(width: 20),
Row(children: [
SvgPicture.network(clubs[index].image,
width: 24.0, height: 24.0,
),
SizedBox(width: 5.0),
clubs[index].name.length > 11
? Text(clubs[index].name
.toString()
.substring(0, 11) +
'...')
: Text(clubs[index].name.toString(), style: textStyle2),
],),
Spacer(),
Container(
width: 28,
child: Text(clubs[index].matches, style: textStyle2),
),
SizedBox(
width: 5,
),
Container(
width: 28,
child: Text(clubs[index].wins, style: textStyle2),
),
SizedBox(
width: 5,
),
Container(
width: 28,
child: Text(clubs[index].draws, style: textStyle2),
),
SizedBox(
width: 5,
),
Container(
width: 28,
child: Text(clubs[index].loss, style: textStyle2),
),
SizedBox(
width: 5,
),
Container(
width: 28,
child: Text((clubs[index].goals - clubs[index].goalsIn).toString(), style: textStyle2),
),
SizedBox(
width: 5,
),
Container(
width: 28,
child: Text(clubs[index].points, style: textStyle2),
),
SizedBox(
width: 5,
),
Container(
width: 5,
height: 20,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.grey[600],
),
padding: EdgeInsets.fromLTRB(10, 5, 2, 5),
),
],
),
);
}
}
class Club {
String name;
String image;
String rank;
String points;
String matches;
String wins;
String loss;
String draws;
int goals;
int goalsIn;
Club(this.name,this.image,this.rank,this.points, this.matches,this.wins,this.loss,this.draws,this.goals,this.goalsIn);
}
I am trying to make my table scrolling because i can not see all of the teams that came from becand due to non scrolling reasons

You are using ListView inside SingleChildScrollView. So set that ListView as non-primary.
primary: false
Change at this point in your code
ListView.builder(
shrinkWrap: true,
primary: false,
// physics: NeverScrollableScrollPhysics(),
itemCount: clubs.length,
itemBuilder: (context, index) {
return TableRow(index: index, clubs:clubs);
},
),

Related

How do i correctly position these items horizontally in flutter to avoid overflow?

I have a list of items that are responsible for a tab bar design, i want to make all the sizedboxes display at a go and not overflow horizontally.
I will give my code for better clarification.
This is what i could come up with after over an hour of tussle:
And this is what i am expecting
I will give my code snippets of the view below.
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
class JobsHeaderWidget extends StatefulWidget {
const JobsHeaderWidget({
Key key,
}) : super(key: key);
#override
State<JobsHeaderWidget> createState() => _JobsHeaderWidgetState();
}
class _JobsHeaderWidgetState extends State<JobsHeaderWidget> {
List<String> items = [
"All",
"Critical",
"Open",
"Closed",
"Overdue",
];
int current = 0;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Jobs',
style: GoogleFonts.poppins(
color: Colors.black, fontSize: 18, fontWeight: FontWeight.w600),
),
Row(
children: [
Text(
'View Insights ',
style: GoogleFonts.poppins(
color: Color(0xff3498DB),
fontSize: 12,
fontWeight: FontWeight.w500),
),
Icon(
Icons.arrow_forward_ios,
color: Color(0xff3498DB),
size: 12,
),
],
),
filterJobs()
],
),
);
}
Widget filterJobs() {
return Container(
width: double.infinity,
child: Column(
children: [
/// CUSTOM TABBAR
SizedBox(
width: double.infinity,
height: 60,
child: ListView.builder(
physics: const BouncingScrollPhysics(),
itemCount: items.length,
scrollDirection: Axis.horizontal,
itemBuilder: (ctx, index) {
return Column(
children: [
GestureDetector(
onTap: () {
setState(() {
current = index;
});
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.all(5),
decoration: BoxDecoration(
color: current == index
? Color(0xff34495E)
: Color(0xffF5F5F5),
borderRadius: BorderRadius.circular(11),
),
child: Center(
child: Padding(
padding: const EdgeInsets.only(
left: 10.0, right: 10.0, top: 5, bottom: 5),
child: Text(
items[index],
style: GoogleFonts.poppins(
fontSize: 10,
fontWeight: FontWeight.w500,
color: current == index
? Colors.white
: Colors.grey),
),
),
),
),
),
],
);
}),
),
// Builder(
// builder: (context) {
// switch (current) {
// case 0:
// return AllNotificationItemsView();
// case 1:
// return JobsNotificationItemsView();
// case 2:
// return MessagesNotificationItemsView();
// case 3:
// return CustomersNotificationItemsView();
// default:
// return SizedBox.shrink();
// }
// },
// )
],
),
);
}
}
The reason for overflow is List View Builder. Remove it and add a Row widget instead. Iterate the list item in it and you will get your desired output.
Full Code : -
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Image',
theme: ThemeData(
primarySwatch: Colors.blue,
),
debugShowCheckedModeBanner: false,
home: const JobsHeaderWidget(),
);
}
}
class JobsHeaderWidget extends StatefulWidget {
const JobsHeaderWidget({super.key});
#override
State<JobsHeaderWidget> createState() => _JobsHeaderWidgetState();
}
class _JobsHeaderWidgetState extends State<JobsHeaderWidget> {
List<String> items = [
"All",
"Critical",
"Open",
"Closed",
"Overdue",
];
int current = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
body: Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10, top: 5),
child: Align(
alignment: Alignment.topCenter,
child: Container(
constraints: const BoxConstraints(maxWidth: 610, maxHeight: 100),
alignment: Alignment.center,
width: double.infinity,
child: IntrinsicWidth(
child: FittedBox(
fit: BoxFit.fitWidth,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
for (int i = 0; i < items.length; i++) ...[
GestureDetector(
onTap: () {
setState(() {
current = i;
});
},
child: AnimatedContainer(
height: 40,
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.all(5),
padding: const EdgeInsets.only(
left: 15.0, right: 15.0, top: 5, bottom: 5),
decoration: BoxDecoration(
color: current == i
? const Color(0xff34495E)
: const Color(0xffF5F5F5),
borderRadius: BorderRadius.circular(11),
),
child: Center(
child: Text(
items[i],
style: GoogleFonts.poppins(
fontSize: 19,
fontWeight: FontWeight.w500,
color: current == i
? Colors.white
: Colors.grey),
),
),
),
),
]
],
),
),
),
),
),
),
);
}
}
Output : -
Hey there for making the appbar not overflowing, you must use expanded widget. try to wrap your gestureDetector or whatever widget that you create for making the design for each listview child like this
Expanded(
child: GestureDetector(
onTap: () {
setState(() {
current = i;
});
},
child: AnimatedContainer(
height: 40,
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.all(5),
padding: const EdgeInsets.only(
left: 15.0, right: 15.0, top: 5, bottom: 5),
decoration: BoxDecoration(
color: current == i
? const Color(0xff34495E)
: const Color(0xffF5F5F5),
borderRadius: BorderRadius.circular(11),
),
child: Center(
child: Text(
items[i],
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color: current == i ? Colors.white : Colors.grey),
),
),
),
),
),
as you can see when you doing this the design will look like this
the text inside of the design would gone because of overflowing issue, you can change the text widget into this widget https://pub.dev/packages/auto_size_text
this is the snipet
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
body: SafeArea(
child: Padding(
padding: const EdgeInsets.only(left: 5.0, right: 5, top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
for (int i = 0; i < items.length; i++) ...[
Expanded(
child: GestureDetector(
onTap: () {
setState(() {
current = i;
});
},
child: AnimatedContainer(
height: 40,
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.all(5),
padding: const EdgeInsets.only(
left: 5.0, right: 5.0, top: 5, bottom: 5),
decoration: BoxDecoration(
color: current == i
? const Color(0xff34495E)
: const Color(0xffF5F5F5),
borderRadius: BorderRadius.circular(11),
),
child: Center(
child: AutoSizeText(
items[i],
maxLines: 1,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color:
current == i ? Colors.white : Colors.grey),
),
),
),
),
),
]
],
),
),
));
but surely the text would be some of big and some of small look like this, and this is the result

flutter layout, Listview builder The relevant error-causing widget was: ListView

my code
in listview, alredy add shrinkWrap: true,
The following assertion was thrown during performLayout():
Assertion failed:
constraints.hasBoundedWidth
is not true
The relevant error-causing widget was:
ListView
When the exception was thrown, this was the stack:
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _isLoading = true;
#override
void didChangeDependencies() {
// ignore: todo
// TODO: implement didChangeDependencies
super.didChangeDependencies();
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
Provider.of<HomeViewModel>(context, listen: false).getWisatas();
setState(() {
_isLoading = false;
});
});
}
#override
Widget build(BuildContext context) {
final modelView = Provider.of<HomeViewModel>(context, listen: true);
return Scaffold(
backgroundColor: cPrimary1,
body: _isLoading
? const Center(child: CircularProgressIndicator())
: SafeArea(
top: true,
bottom: true,
child: Column(
children: <Widget>[
Expanded(
flex: 2,
child: Stack(
children: [
Container(
height: 220,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(width: 5, color: CSeccond)),
image: DecorationImage(
image: AssetImage("assets/tugumangga.jpeg"),
fit: BoxFit.fill,
alignment: Alignment.bottomCenter),
),
),
Positioned(
top: 30,
left: 20,
child: RichText(
text: TextSpan(
text: "Selamat\nDatang",
style: TextStyle(
fontSize: 36,
color: Colors.white,
),
),
),
),
],
),
),
Expanded(
flex: 5,
child: Padding(
padding: EdgeInsets.only(right: 20, left: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Wisata Alam',
style: TextStyle(
fontSize: 18,
color: Colors.white,
),
),
SizedBox(
height: 8,
),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ListView.builder(
itemCount: modelView.wisatalist.length,
physics: BouncingScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, index) {
return GestureDetector(
child: BoxWisata(
h: 100,
w: 100,
fs: 13,
title: 'wisata',
img: 'assets/tugumangga.jpeg',
),
onTap: () => {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) =>
// DetailScreen(
// nama: modelView
// .wisatalist[index]
// .nama,
// img: [],
// ),
// ))
});
}),
// BoxWisata(
// h: 100,
// w: 100,
// fs: 13,
// title: 'wisata',
// img: 'assets/tugumangga.jpeg',
// ),
// BoxWisata(
// h: 100,
// w: 100,
// fs: 13,
// title: 'wisata',
// img: 'assets/tugumangga.jpeg'),
// BoxWisata(
// h: 100,
// w: 100,
// fs: 13,
// title: 'wisata',
// img: 'assets/tugumangga.jpeg'),
// BoxWisata(
// h: 100,
// w: 100,
// fs: 13,
// title: 'wisata',
// img: 'assets/tugumangga.jpeg'),
// BoxWisata(
// h: 100,
// w: 100,
// fs: 13,
// title: 'wisata',
// img: 'assets/tugumangga.jpeg'),
],
),
),
],
),
)),
],
),
),
);
}
}
my widget box
import 'package:flutter/material.dart';
class BoxWisata extends StatelessWidget {
final String title;
final String img;
final double h;
final double w;
final double fs;
BoxWisata({
Key? key,
required this.title,
required this.img,
required this.h,
required this.w,
required this.fs,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
width: w,
height: h,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(25),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.6),
offset: const Offset(
0.0,
10.0,
),
blurRadius: 10.0,
spreadRadius: -6.0,
),
],
image: DecorationImage(
image: AssetImage(img),
fit: BoxFit.cover,
),
),
child: Stack(children: [
Align(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
child: Text(
title,
style: TextStyle(
fontSize: fs,
color: Colors.black,
fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis,
maxLines: 2,
textAlign: TextAlign.center,
),
),
alignment: Alignment.center,
)
]),
);
}
}
errorcode
he following assertion was thrown during performLayout():
Assertion failed:
constraints.hasBoundedWidth
is not true
The relevant error-causing widget was:
ListView
When the exception was thrown, this was the stack:
This might help
Column(
children: <Widget>[
Stack(
children: [
Container(
height: 220,
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(width: 5, color: Colors.green),
),
image: DecorationImage(
image: NetworkImage("https://picsum.photos/200/300"),
fit: BoxFit.fill,
alignment: Alignment.bottomCenter,
),
),
),
Positioned(
top: 30,
left: 20,
child: RichText(
text: const TextSpan(
text: "Selamat\nDatang",
style: TextStyle(
fontSize: 36,
color: Colors.white,
),
),
),
),
],
),
const Text(
'Wisata Alam',
style: TextStyle(
fontSize: 18,
color: Colors.white,
),
),
const SizedBox(height: 8),
Expanded(
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: 100,
physics: const BouncingScrollPhysics(),
itemBuilder: (context, index) {
return GestureDetector(
child: Container(
padding: const EdgeInsets.all(12),
alignment: Alignment.center,
color: Colors
.primaries[Random().nextInt(Colors.primaries.length)],
child: Text('wisata $index'),
),
onTap: () => {},
);
},
),
),
],
);

ReorderbleList with Draggable Widgets does not work

I have a ReorderdableList with 5 Widgets and each of them is Draggable.
The Draggable Widget works great, but it seems that this makes the onReorder function not work.
This is my ReorderableListView:
return Scaffold(
body: ReorderableListView(
onReorder: ((oldIndex, newIndex) {
print('onReorder');
}),
onReorderStart: (index) => print('reorder start'),
scrollDirection: Axis.horizontal,
children: [
for (final card in handCards)
HandCard(key: ValueKey(card), card, player, handOwner),
],
),
);
Each Handcard returns a Draggable Widget. Is there a way to make sure both still work?
Handcard Widget:
class HandCard extends ConsumerStatefulWidget {
HandCard(this.card, this.player, this.handOwner, {Key? key})
: super(key: key);
String handOwner;
dynamic card;
Player player;
#override
_HandCardState createState() => _HandCardState();
}
class _HandCardState extends ConsumerState<HandCard> {
#override
void initState() {
isVisibled = true;
// TODO: implement initState
super.initState();
print(isVisibled);
}
void setVisible() {
setState(() {
isVisibled = true;
});
}
late bool isVisibled;
#override
Widget build(BuildContext context) {
var handCardPickProvider =
ref.watch(handCardHighlightProvider(widget.card).notifier);
var handCardPick = ref.watch(handCardHighlightProvider(widget.card));
var gameStateProvider = ref.watch(GameStateProvider);
var handSize = ref.watch(handSizeProvider(widget.handOwner).state);
return Draggable<HandCard>(
onDragStarted: () {
// change state of current cards in hand
handSize.state = handSize.state - 1;
},
onDragEnd: (details) {
handSize.state = handSize.state + 1;
},
onDragCompleted: () {
setState(() {
isVisibled = true;
});
},
data: widget,
childWhenDragging: SizedBox.shrink(),
feedback: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(widget.card.imageLink),
fit: BoxFit.fill,
),
),
width: 100,
height: 150,
child: Stack(children: [
(widget.card is CharacterCard)
? Positioned(
right: 0,
left: 60,
child: Container(
color: Colors.white,
width: 40,
height: 13,
child: Center(
child: Text(
widget.card.power.toString(),
style: TextStyle(
color: Colors.black,
fontSize: 10,
fontWeight: FontWeight.bold),
),
),
),
)
: const SizedBox.shrink(),
Positioned(
left: 2,
child: Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
child: Center(
child: Text(
widget.card.cost.toString(),
style: TextStyle(color: Colors.white, fontSize: 12),
)),
))
]),
),
child: (isVisibled)
? InkWell(
onTap: () {
print('click');
// If it is the counter move and the card has a counter effect we can use it
if (gameStateProvider.gameSession!.moves.length != 0) {
Move currentMove = gameStateProvider.gameSession!
.moves[gameStateProvider.gameSession!.atMove - 1];
print(currentMove.moveType);
// Handle on counter effect
if (currentMove.moveType == 'on counter effect' &&
currentMove.toPlayer.id == widget.player.id) {
handCardPickProvider.highlightCard(widget.card);
}
}
},
child: Container(
margin: EdgeInsets.all(1),
decoration: BoxDecoration(
boxShadow: [
(handCardPick)
? BoxShadow(
color: Colors.white,
spreadRadius: 1,
blurRadius: 10)
: BoxShadow(
color: Colors.white,
spreadRadius: 0,
blurRadius: 0),
],
image: DecorationImage(
image: AssetImage(widget.card.imageLink),
fit: BoxFit.fill,
),
),
width: 100,
height: 150,
child: Stack(children: [
(widget.card is CharacterCard)
? Positioned(
right: 0,
left: 60,
child: Container(
color: Colors.white,
width: 40,
height: 13,
child: Center(
child: Text(
widget.card.power.toString(),
style: TextStyle(
color: Colors.black,
fontSize: 10,
fontWeight: FontWeight.bold),
),
),
),
)
: const SizedBox.shrink(),
Positioned(
left: 2,
child: Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
child: Center(
child: Text(
widget.card.cost.toString(),
style: TextStyle(color: Colors.white, fontSize: 12),
)),
))
]),
),
)
: SizedBox.shrink(),
);
}
}

geting data from firebase in flutter

im trying to get data from firebase
the main page show the data correctly based on the length
but the details page is not the data of the first index is duplicated to the on the other pages
this is the main page and it shows different data correctly
but the first details page keep duplicate it self
this is the detail page code
import 'package:carousel_slider/carousel_slider.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:online_shop/api/summer_list_api.dart';
import 'package:online_shop/core/services/summer_notifier.dart';
import 'package:online_shop/model/Summer_d_model.dart';
import 'package:online_shop/pages/home_page.dart';
import 'package:online_shop/view/widgets/costum_button.dart';
import 'package:online_shop/view/widgets/costum_text.dart';
import 'package:online_shop/view/widgets/nav.dart';
import 'package:provider/provider.dart';
class DetalsPage extends StatefulWidget {
DetalsPage({Key? key}) : super(key: key);
#override
_DetalsPage createState() => _DetalsPage();
}
class _DetalsPage extends State<DetalsPage> {
late Future Summers;
#override
void initState() {
Summers = getsummerinfo(SummerNotifier());
super.initState();
}
#override
Widget build(BuildContext context) {
SummerNotifier summerNotifier = Provider.of<SummerNotifier>(context);
return Scaffold(
body: ListView.builder(
itemCount: 1,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return Column(
children: [
Container(
child: Stack(
children: [
Image.network(
summerNotifier.summerList[index].Imag,
width: 400,
fit: BoxFit.fitWidth,
),
Container(
margin: const EdgeInsets.only(top: 40, left: 5),
child: IconButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return Nav();
}));
},
icon: Icon(Icons.arrow_back_ios))),
Container(
height: 575,
margin: const EdgeInsets.only(top: 230),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20)),
child: Padding(
padding: const EdgeInsets.only(top: 5, bottom: 5),
child: ListView.builder(
itemCount: 1,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return Column(
children: [
Padding(
padding: const EdgeInsets.only(
left: 10,
),
child: CoustumText(
text: summerNotifier.summerList[index].name,
size: 30,
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
const SizedBox(
height: 10,
),
Padding(
padding: const EdgeInsets.only(
left: 10, right: 10),
child: CoustumText(
text: summerNotifier
.summerList[index].sub_info,
size: 16,
color: Colors.black,
),
),
const SizedBox(height: 20),
Padding(
padding: const EdgeInsets.only(left: 10),
child: CoustumText(
text: "some of the place photos:",
size: 18,
color: Colors.black,
fontWeight: FontWeight.w600,
),
),
const SizedBox(
height: 10,
),
FutureBuilder(
future: Summers,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text("there is issu ");
case ConnectionState.waiting:
return CircularProgressIndicator();
default:
if (snapshot.hasError) {
return Text("Error");
}
}
return CarouselSlider(
items: summerNotifier
.summerList[index].sub_img
?.map((items) => Container(
height: 200,
child: Image.network(
items,
fit: BoxFit.cover,
),
))
.toList(),
options:
CarouselOptions(autoPlay: false),
);
}),
const SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.only(left: 10),
child: CoustumText(
text: "trip informations:",
size: 20,
color: Colors.black,
fontWeight: FontWeight.w600,
),
),
const SizedBox(
height: 10,
),
Padding(
padding: const EdgeInsets.only(
left: 10, right: 10),
child: Container(
child: CoustumText(
text:
"The trip is for 7 days and 8 nights and ther will be a program for spinding the time,every day ther will be a new place to discover so relax and lets the journy start.",
size: 16,
color: Colors.black,
),
),
),
const SizedBox(
height: 20,
),
Container(
child: Padding(
padding: const EdgeInsets.only(
left: 10, right: 10),
child: Column(
children: [
CoustumText(
text: "Contact informations:",
size: 20,
color: Colors.black,
fontWeight: FontWeight.w600,
),
SizedBox(
height: 10,
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Row(
children: const [
Icon(
Icons.phone,
size: 20,
),
SizedBox(
width: 5,
),
CoustumText(
text: "85746385",
size: 16,
color: Colors.black),
],
),
Row(
children: const [
Icon(
Icons.facebook_rounded,
color: Colors.blueAccent,
size: 30,
),
SizedBox(
width: 5,
),
CoustumText(
text: "Flay_fun",
size: 16,
color: Colors.black),
],
),
],
),
const SizedBox(
height: 5,
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Row(
children: const [
Icon(
Icons.phone,
size: 20,
),
SizedBox(
width: 5,
),
CoustumText(
text: "85208579",
size: 16,
color: Colors.black),
],
),
Row(
children: const [
Icon(
Icons.email_rounded,
color: Colors.blueAccent,
size: 30,
),
SizedBox(
width: 5,
),
CoustumText(
text: "Flayfun#gmail.com",
size: 16,
color: Colors.black),
],
),
],
),
],
),
),
),
const SizedBox(
height: 20,
),
Container(
width: 200,
child: CoustumButton(
text: "book now \$200",
onPressed: () {},
size: 20,
),
),
],
);
},
),
),
),
],
),
),
],
);
},
),
);
}
}
this is the method to get the data
// ignore_for_file: unused_local_variable, non_constant_identifier_names
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:online_shop/core/services/summer_notifier.dart';
import 'package:online_shop/model/Summer_d_model.dart';
Future getsummerinfo (SummerNotifier summerNotifier) async {
QuerySnapshot snapshot =
await FirebaseFirestore.instance.collection("Summer_D").get();
List<Summer_d> _summerList = [];
snapshot.docs.forEach((docs) {
Summer_d summer_d = Summer_d.fromMap(docs.data() as Map<String, dynamic>);
_summerList.add(summer_d);
});
summerNotifier.summerList = _summerList;
}
this is the other one
// ignore_for_file: unused_local_variable, non_constant_identifier_names
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:online_shop/core/services/summer_notifier.dart';
import 'package:online_shop/model/Summer_d_model.dart';
Future getsummerinfo (SummerNotifier summerNotifier) async {
QuerySnapshot snapshot =
await FirebaseFirestore.instance.collection("Summer_D").get();
List<Summer_d> _summerList = [];
snapshot.docs.forEach((docs) {
Summer_d summer_d = Summer_d.fromMap(docs.data() as Map<String, dynamic>);
_summerList.add(summer_d);
});
summerNotifier.summerList = _summerList;
}
this is the models
// ignore_for_file: camel_case_types
class Summer_d {
late String Imag;
late String info;
late String name;
late int price;
late String sub_info;
late List<dynamic>? sub_img;
Summer_d.fromMap(Map<String,dynamic>data){
Imag = data["Imag"];
info = data ["info"];
name = data ["name"];
price = data["price"];
sub_info = data ["sub_info"];
sub_img = data ["sub_img"];
}
}
You're hardcoding the itemCount in the ListView.builder, and then in the ListView.builder, in its itemBuilder method, you're saying summerNotifier.summerList[index]. The index will always be zero.
#override
Widget build(BuildContext context) {
SummerNotifier summerNotifier = Provider.of<SummerNotifier>(context);
return Scaffold(
body: ListView.builder(
itemCount: 1, // hard-coding this to 1
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
// here the index will always be zero,
// since above you specified itemCount = 1
summerNotifier.summerList[index]
}
)
);
}
I'd actually use the SummerNotifier service you have to hold on to the selected item reference and then in the Details page I get it from the service and populate the details of that item. Or in your case, the index of the selected item.
I believe that's your issue.

flutter Problem same quantity show on products

when I am increasing my quantity of one product then all product's quantity is increasing, so how to solve it.
This is my product page:
import 'dart:convert';
import 'package:carousel_pro/carousel_pro.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:hospital/Authentication/LoginLogoutScreenPage/login.dart';
import 'package:hospital/CartPage/Cart_Api/cart_api.dart';
import 'package:hospital/CartPage/pages/cartPage.dart';
import 'package:hospital/Drawer/dropdown_menu.dart';
import 'package:hospital/ProductDetailsPage/product_detailPage.dart';
import 'package:hospital/ProductDetailsPage/related_product_page.dart';
import 'package:hospital/SecondSection/Medicine/medicine_page.dart';
import 'package:hospital/constant.dart';
import 'package:hospital/customApiVariable.dart';
import 'package:http/http.dart' as http;
import 'package:line_icons/line_icons.dart';
import 'package:provider/provider.dart';
class DetailPage extends StatefulWidget {
final plistId;
const DetailPage({Key key, this.plistId}) : super(key: key);
#override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
final GlobalKey<FormState> _formKey = GlobalKey();
int quantity = 1;
var response;
var detailPageApi;
#override
void initState() {
super.initState();
fetchData(widget.plistId);
}
fetchData(var consultWithDoctor) async {
var api = Uri.parse(
'$ecommerceBaseUrl/productListApi.php?a2rTokenKey=$a2rTokenKey&plistId=${widget.plistId}');
response = await http.get(
api,
);
print("detailPageApi " + api.toString());
print("detailPageBody " + response.body);
detailPageApi = jsonDecode(response.body);
print("detailPagelist " + detailPageApi.toString());
setState(() {});
}
Future _submit() async {
var errorMessage = 'Authentication Failed';
if (successfully_add_cart_status.toString() == 'false') {
errorMessage = 'Please try again later';
print(errorMessage);
_showerrorDialog(errorMessage);
} else {
errorMessage = 'Product Succesfully Added to Cart';
print(errorMessage);
_showerrorDialog(errorMessage);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: kGreen,
title: Text(
"Details",
style: TextStyle(fontStyle: FontStyle.italic),
),
actions: [
IconButton(
icon: Icon(Icons.shopping_cart),
// onPressed: () => print("open cart"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Cartpage()),
);
},
),
DropDownMenu(),
],
),
body: Container(
child: response != null
? ListView.builder(
itemCount: detailPageApi.length.clamp(0, 1),
scrollDirection: Axis.vertical,
physics: ScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, index) {
var details = detailPageApi[index];
if (details['num'] == 0) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.white,
),
);
}
return Column(
children: <Widget>[
Hero(
tag: "1",
child: SizedBox(
height: 300.0,
width: 300.0,
child: Carousel(
boxFit: BoxFit.cover,
autoplay: false,
animationCurve: Curves.fastOutSlowIn,
animationDuration: Duration(milliseconds: 800),
dotSize: 6.0,
dotIncreasedColor: Colors.black,
dotBgColor: Colors.transparent,
// dotPosition: DotPosition.topRight,
dotVerticalPadding: 10.0,
showIndicator: true,
indicatorBgPadding: 7.0,
images: [
NetworkImage(details['pImgImg']),
],
),
),
),
SizedBox(
height: 50,
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Name :",
style: TextStyle(
fontSize: 18,
height: 1.5,
fontWeight: FontWeight.w500),
),
SizedBox(
width: 20,
),
Flexible(
child: Text(
// widget.details,
details['productName'],
style: TextStyle(
fontSize: 17,
height: 1.5,
fontWeight: FontWeight.w500),
),
),
],
),
),
SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Details :",
style: TextStyle(
fontSize: 18,
height: 1.5,
fontWeight: FontWeight.w500),
),
SizedBox(
width: 20,
),
Flexible(
child: Text(
// widget.details,
details['productDescription'],
style: TextStyle(
fontSize: 17,
height: 1.5,
fontWeight: FontWeight.w500),
),
),
],
),
),
SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20),
child: Row(
children: <Widget>[
Text(
"Price :",
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.w500),
),
SizedBox(
width: 20,
),
Row(
children: <Widget>[
Text(
// "Rs " + widget.pPromotionPrice,
"Rs 55.0",
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.w500),
),
SizedBox(
width: 20,
),
Text(
// "Rs " + widget.pPrice,
"Rs 100",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
// color: warning,
decoration: TextDecoration.lineThrough),
)
],
)
],
),
),
SizedBox(
height: 25,
),
Padding(
padding: const EdgeInsets.only(right: 20, left: 20),
child: Row(
children: <Widget>[
Text(
"Qty :",
style: TextStyle(
fontSize: 17, fontWeight: FontWeight.w500),
),
SizedBox(
width: 20,
),
Row(
children: <Widget>[
InkWell(
onTap: () {
if (quantity > 1) {
setState(() {
quantity = --quantity;
});
}
// minus here
},
child: Container(
width: 25,
height: 25,
decoration: BoxDecoration(
// border: Border.all(color: primary),
shape: BoxShape.circle),
child: Icon(
LineIcons.minus,
size: 15,
),
),
),
SizedBox(
width: 15,
),
Text(
quantity.toString(),
style: TextStyle(fontSize: 16),
),
SizedBox(
width: 15,
),
InkWell(
onTap: () {
setState(() {
quantity = ++quantity;
});
// minus here
},
child: Container(
width: 25,
height: 25,
decoration: BoxDecoration(
// border: Border.all(color: primary),
shape: BoxShape.circle),
child: Icon(
LineIcons.plus,
size: 15,
),
),
),
],
)
],
),
),
SizedBox(
height: 50,
),
InkWell(
onTap: () async {
if (var_uid.toString() != null.toString()) {
_submit();
var qty = quantity.toString();
var plistId = widget.plistId;
print('pplistid' + plistId);
var uid = var_uid.toString();
var sid = var_sid.toString();
print('uuid' + uid);
print('ssid' + sid);
var response =
await add_to_cart_fn(qty, plistId, uid, sid);
print("rsp: " + response['msg']);
} else {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => LoginPage()));
}
},
// },
child: Padding(
padding: EdgeInsets.only(left: 20, right: 20),
child: Container(
height: 45,
width: double.infinity,
decoration: BoxDecoration(
color: kGreen,
borderRadius: BorderRadius.circular(30)),
child: Center(
child: Text(
"ADD TO CART",
style: TextStyle(
color: kWhite,
fontSize: 20,
),
),
),
),
),
),
SizedBox(height: 20.0),
RelatedProductPage(plistId: widget.plistId)
],
);
})
: Center(
child: CircularProgressIndicator(
backgroundColor: Colors.white,
),
),
),
);
}
void _showerrorDialog(String message) {
Fluttertoast.showToast(
msg: message,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1,
backgroundColor: Colors.grey[350],
textColor: Colors.black,
fontSize: 16.0);
}
}
You are using the same quantity variable against each item. Changing the value on one of those will cause all items to update. What you need to do is to keep a Map of quantity selected against product id. That way whenever you increase or decrease the quantity, you update the quantity against that specific product id and the rest will remain unchanged.
EDIT: Here is how this will work
//Create a new map to save the product id and product selected quantity
var productQuantity = new Map<int, int>()
//When setting the values of the product, set the quantity from the map
Padding(
padding: const EdgeInsets.only(right: 20, left: 20),
child: Row(
children: <Widget>[
Text(
"Qty :",
style: TextStyle(
fontSize: 17, fontWeight: FontWeight.w500),
),
SizedBox(width: 20,),
Row(
children: <Widget>[
InkWell(
onTap: () {
if (quantity > 1) {
setState(() {
//Changed here
productQuantity['$productId'] -= 1;
});
}
},
child: Container(
width: 25,
height: 25,
decoration: BoxDecoration(shape: BoxShape.circle),
child: Icon(
LineIcons.minus,
size: 15,
),
),
),
SizedBox(width: 15,),
Text(
//Changed here
productQuantity['$productId'].toString(),
style: TextStyle(fontSize: 16),
),
SizedBox(width: 15,),
InkWell(
onTap: () {
setState(() {
//Changed here
productQuantity['$productId'] += 1;
});
},
child: Container(
width: 25,
height: 25,
decoration: BoxDecoration(
shape: BoxShape.circle),
),
child: Icon(
LineIcons.plus,
size: 15,
),
),
),
],
)
],
),
)
you set the common quantity in all products so change it and set it inside the class.
Please Check the example
import 'package:flutter/material.dart';
class QuantityUpdatePage extends StatefulWidget {
#override
_QuantityUpdatePageState createState() => _QuantityUpdatePageState();
}
class _QuantityUpdatePageState extends State<QuantityUpdatePage> {
List<Product> productArray = [];
#override
void initState() {
super.initState();
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
productArray.clear();
productArray.add(Product(1, "Product 1", 1));
productArray.add(Product(2, "Product 2", 1));
productArray.add(Product(3, "Product 3", 1));
productArray.add(Product(4, "Product 4", 1));
productArray.add(Product(5, "Product 5", 1));
setState(() {});
});
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("QUANTITY UPDATE")),
body: ListView.builder(
shrinkWrap: true,
itemCount: productArray.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.only(right: 20, left: 20),
child: ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
children: [
SizedBox(
height: 20,
),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(productArray[index].productName),
SizedBox(
width: 40,
),
Row(
children: <Widget>[
Text(
"Qty :",
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w500),
),
SizedBox(
width: 20,
),
Row(
children: <Widget>[
InkWell(
onTap: () {
if (productArray[index].quantity > 1) {
setState(() {
productArray[index].quantity = --productArray[index].quantity;
});
}
// minus here
},
child: Container(
width: 25,
height: 25,
decoration: BoxDecoration(
// border: Border.all(color: primary),
shape: BoxShape.circle),
child: Icon(
Icons.minimize,
size: 15,
),
),
),
SizedBox(
width: 15,
),
Text(
productArray[index].quantity.toString(),
style: TextStyle(fontSize: 16),
),
SizedBox(
width: 15,
),
InkWell(
onTap: () {
setState(() {
productArray[index].quantity = ++productArray[index].quantity;
});
// minus here
},
child: Container(
width: 25,
height: 25,
decoration: BoxDecoration(
// border: Border.all(color: primary),
shape: BoxShape.circle),
child: Icon(
Icons.add,
size: 15,
),
),
),
],
)
],
),
],
),
SizedBox(
height: 20,
),
],
),
);
}));
}
}
class Product {
String productName;
int quantity;
int id;
Product(this.id, this.productName, this.quantity);
}
#Deepak if you don't understand Maps use list instead, with a value being updated for each index. Initialize a list of int types with some large values like 1000000, and update the value for each index. use ListView builder to fetch the data from the API for each index.
List<int> quantity = List.empty(growable: true);
OR
List<int> quantity = List.filled(10000, []);
For updating quantity:-
quantity[index] += 1;
For Grid view thing, refer this example from CodeGrepper:-
GridView.count(
// Create a grid with 2 columns. If you change the scrollDirection to
// horizontal, this produces 2 rows.
crossAxisCount: 2,
// Generate 100 widgets that display their index in the List.
children: List.generate(100, (index) {
return Center(
child: Text(
'Item $index',
style: Theme.of(context).textTheme.headline5,
),
);
}),
);