Flutter/Dart: Create a GridView where the first item is a unique grid item - flutter

I am new to Flutter and Dart but I have a grid view on one of my screens and I want the first grid item to be a unique button that allows the user to add a student. You can see in the image below an example of what I am trying to accomplish. How do I create a unique view with the first item allowing a user to add a student?
Grid Class:
body: Padding(
padding: const EdgeInsets.only(left: 15.0, right: 15.0),
child: Column(
children: <Widget>[
ProfileHeader(),
ProfileViewSwitch(),
ProfileSearch(),
Flexible(
//Below is the GridView used for each student in the class
child: GridView(
//TODO convert to a builder for performance efficiency
padding: const EdgeInsets.only(top: 10.0),
children: DUMMY_CATEGORIES
.map(
(catData) => ImageItem(
catData.firstName,
catData.lastName,
catData.color,
catData.initials,
),
)
.toList(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
//maxCrossAxisExtent: 150,
crossAxisCount: 3,
childAspectRatio: 1,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
),
),
],
),
),
Image Item Class:
Widget build(BuildContext context) {
return InkWell(
onTap: () => selectCategory(context),
borderRadius: BorderRadius.circular(15),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
child: new Column(
children: <Widget>[
ClipOval(
child: Material(
color: color, // button color
child: InkWell(
//splashColor: Colors.red, // inkwell color
child: SizedBox(
width: 80,
height: 80,
child: Align(
alignment: Alignment.center,
child: Text(initials,
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 35)),
),
),
),
),
)
],
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
//crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
child: new Column(
children: <Widget>[
new Text(
firstName,
textAlign: TextAlign.center,
style:
TextStyle(fontWeight: FontWeight.bold, fontSize: 15),
),
new Text(
lastName,
textAlign: TextAlign.center,
style:
TextStyle(fontWeight: FontWeight.bold, fontSize: 15),
),
],
),
),
],
),
],
),
);
}
}

You can achieve the desired result in two ways,
Method 1: Using GridView,builder, return your Button at index 0 - I'd recommend to using this method.
GridView.builder(
//TODO convert to a builder for performance efficiency
padding: const EdgeInsets.only(top: 10.0),
itemCount: DUMMY_CATEGORIES.length + 1,
itemBuilder: (context, i) {
if (i == 0) {
return IconButton(
icon: Icon(Icons.add),
onPressed: () {},
);
}
final catData = DUMMY_CATEGORIES[i - 1];
return ImageItem(
catData.firstName,
catData.lastName,
catData.color,
catData.initials,
);
},
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
//maxCrossAxisExtent: 150,
crossAxisCount: 3,
childAspectRatio: 1,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
)
Method 2: Concat a null or unique value in from and handle during map
GridView(
//TODO convert to a builder for performance efficiency
padding: const EdgeInsets.only(top: 10.0),
children: [null, ...DUMMY_CATEGORIES].map(
(catData) {
if (catData == null) {
return IconButton(
icon: Icon(Icons.add),
onPressed: () {},
);
}
return ImageItem(
catData.firstName,
catData.lastName,
catData.color,
catData.initials,
);
},
).toList(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
//maxCrossAxisExtent: 150,
crossAxisCount: 3,
childAspectRatio: 1,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
)
Hope that helps!

Related

Flutter: Make all screen scrollable with GridView.builder inside

In my home screen my app shows carousel first then a vertical list of challenges cards retrieved from Cloud Firestore using GridView.builder as follows:
GridView.builder(
scrollDirection: Axis.vertical,
itemCount: _challenges.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
childAspectRatio: MediaQuery.of(context).size.width /
(MediaQuery.of(context).size.height / 4),
),
itemBuilder: (context, index) {
return InkWell(
onTap: () {
if (_challenges[index]["isLocked"] == "true") {
showLockedDialog();
} else {
checkParticipation(index);
if (checkPart == true) {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) =>
ChallengeDetails(_challenges[index])));
}
checkPart = true;
}
},
child: Stack(
children: [
Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(15),
child: Image(
image: NetworkImage(_challenges[index]["image-path"]),
fit: BoxFit.cover,
height: 150,
width: 350,
opacity: _challenges[index]["isLocked"] == "true"
? AlwaysStoppedAnimation(.4)
: null,
),
),
),
Center(
child: Text(
"${_challenges[index]["name"]}\n",
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold),
),
),
Center(
child: Text(
"\n${_challenges[index]["date"]}",
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold),
textDirection: TextDirection.ltr,
)),
Center(
child: SizedBox(
height: 130,
width: 130,
child: _challenges[index]["isLocked"] == "true"
? Image.asset("assets/lock-icon.jpg")
: null,
),
)
],
),
);
});
Everything retrieving fine and it is rendered in my home_screen as follows:
body: Column(
children: [
AdsBanner(),
SizedBox(
height: 30,
),
Padding(
padding: const EdgeInsets.only(right: 8, left: 8, bottom: 5),
child: Row(
children: [
Text(
AppLocalizations.of(context)!.challenges + " ",
style: TextStyle(fontSize: 20),
),
Text(
AppLocalizations.of(context)!.clickToParticipate,
style: TextStyle(fontSize: 15),
)
],
),
),
Expanded(child: ChallengeCard()),
],
),
The problem is that only the GridView area is scrolling and what am seeking for is to scroll the whole screen with the GridView area, I was trying to use the CustomScrollView() but its not working properly.
I'll be thankful for any help.
First in your GridView.builder add these:
GridView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
...
)
then in your home_screen wrap your column with SingleChildScrollView:
SingleChildScrollView(
child: Column(
children: [
AdsBanner(),
SizedBox(
height: 30,
),
Padding(
...
),
),
You can provide physics: NeverScrollableScrollPhysics() on GridView to disable scroll effect. If you want scrollable as secondary widget use primary: false, to have Full Page scrollable, you can use body:SingleChildScrollView(..) or better using body:CustomScrollView(..)

set left widget as focused one in flutter

I am using card_swiper widget in my project. It is a good library, but there is a problem: the focused widget always stays on centre but I want the focused item to be the one on the left. How can I accomplish this with this library?
In the below picture, focused item is on centre, but yellow item, in my case, should be on the left.
I found the answer which could be useful for others. The example is for 4 items on view but you can customise it to as many as you want:
Scaffold(
backgroundColor: AppColors.purpleDark,
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Flexible(
child: Swiper(
index: chosenIndex,
layout: SwiperLayout.CUSTOM,
physics: BouncingScrollPhysics(),
customLayoutOption: CustomLayoutOption(
startIndex: 0,
stateCount: math.min(4, listSize),
).addScale(
[3, 1, 1, 1], // there should be 4 widgets in view with the first 3 times larger
Alignment.topRight,
).addTranslate( // place the 4 items as I want
[
Offset(-35.toResizableWidth(), 0),
Offset(30.toResizableWidth(), 0.0),
Offset(118.toResizableWidth(), 0.0),
Offset(200.toResizableWidth(), 0.0),
],
),
itemWidth: 51.toResizableWidth(),
itemHeight: 51.toResizableHeight(),
controller: controller,
itemCount: listSize,
onIndexChanged: (newIndex) => setState(() => chosenIndex = newIndex),
itemBuilder: (context, index) {
return GestureDetector(
onTap: () => controller.next(),
child: Container(
width: 51.toResizableWidth(),
height: 51.toResizableHeight(),
color: Colors.grey,
child: Center(
child: Text(
'$index',
style: AppTextStyles.styleS16W600.copyWith(color: Colors.white),
),
),
),
);
},
),
),
Padding(
padding: EdgeInsets.symmetric(
vertical: 10.toResizableHeight(),
horizontal: 20.toResizableWidth(),
),
child: Text(
LocaleKeys.rewards_day.tr(args: <String>[chosenIndex.toString()]),
style: AppTextStyles.styleS20W600
.copyWith(color: true ? AppColors.greenPositive : AppColors.redNegative),
),
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: 20.toResizableWidth(),
),
child: Text(
longText,
style: AppTextStyles.styleS16W400.copyWith(color: AppColors.white100),
),
),
Expanded(child: Container()),
],
),
);

Flutter how to remove gridview top space

I am getting a space on top of my gridview. I have tried to remove it without success.
It looks like this:
What I want:
Here is my code:
Container(
margin: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Check",
style: TextStyle(color: Colors.black, fontSize: 18, fontWeight: FontWeight.bold),
textAlign: TextAlign.left,
),
GridView.count(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
crossAxisCount: 1,
crossAxisSpacing: 2,
mainAxisSpacing: 10,
childAspectRatio: 5.1,
children: <Widget>[
GestureDetector(
child: _buildWidget("Car", 0),
onTap: () => setState(() => _languageIndex = 0),
),
GestureDetector(
child: _buildWidget("Boat", 1),
onTap: () => setState(() => _languageIndex = 1),
),
],
),
],
));
Widget _buildWidget(String language, int index) {
bool isSelected = _languageIndex == index;
return Container(
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
border: Border.all(color: isSelected ? Colors.blue.withOpacity(1.0) : Colors.black26),
color: isSelected ? Colors.white.withOpacity(0.0) : Colors.white
),
child:
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(width:10),
Text(
language,
style: TextStyle(fontSize: 16,fontWeight: FontWeight.bold, color: isSelected ? Colors.black : Colors.black26),
),
SizedBox(width:20),
],)
);
}
What can I do to remove the space between the text and the gridview? Or can I do it in another way to get the output I am looking for?
The GridView widget has a default padding, you can remove the padding by giving it a padding of EgdeInsets.zero.
GridView.count(
padding: EdgeInsets.zero // set padding to zero
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
crossAxisCount: 1,
crossAxisSpacing: 2,
mainAxisSpacing: 10,
childAspectRatio: 5.1,
children: <Widget>[
GestureDetector(
child: _buildWidget("Car", 0),
onTap: () => setState(() => _languageIndex = 0),
),
GestureDetector(
child: _buildWidget("Boat", 1),
onTap: () => setState(() => _languageIndex = 1),
),
],
),

How to fix "Could not find the correct Provider<Product> above this ProductItem Widget "?

I am very much new to flutter. This is my first time using providers. I have been through every solution out there but nothing seems to help.
In a shopping app I am developing, I tried to use the provider package to pass data to my widget dynamically.
I am sharing the code and the screenshot of the very big error message. Hope somebody could help
Gridview builder
final productData = Provider.of<ProductsProvider>(context);
final products = productData.items;
return GridView.builder(
padding: EdgeInsets.all(10),
itemCount: products.length,
itemBuilder: (context, index) => ChangeNotifierProvider.value(
value: products[index], child: ProductItem()),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.75,
crossAxisSpacing: 10,
mainAxisSpacing: 10),
);
Individual product item in the grid
final product = Provider.of<Product>(context);
return Container(
child: GestureDetector(
onTap: () {
Navigator.of(context)
.pushNamed(ProductDetails.routeName, arguments: product.id);
},
child: Card(
color: Colors.white,
elevation: 6,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
//product image
Image(image: AssetImage(product.imageUrl)),
Padding(
padding: EdgeInsets.symmetric(vertical: 0, horizontal: 10),
//item name and fav button
child: Flex(
direction: Axis.horizontal,
children: <Widget>[
Expanded(
child: Text(
product.name,
style: Theme.of(context)
.textTheme
.headline1
.copyWith(fontSize: 16, color: Colors.black),
)),
IconButton(
icon: Icon(
product.isFav
? Icons.favorite
: Icons.favorite_border,
color: Colors.red,
),
onPressed: () {
product.toggleFav();
})
],
),
),
// price and buy button
Padding(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
child: Flex(
direction: Axis.horizontal,
children: <Widget>[
Expanded(
child: Text(
"\$ " + product.price.toString(),
style: Theme.of(context).textTheme.headline1.copyWith(
color: Theme.of(context).primaryColor, fontSize: 15),
)),
SizedBox(
width: 60,
child: RaisedButton(
onPressed: () {},
color: Colors.orange,
child: Text(
"Buy",
style: TextStyle(fontFamily: 'Prompt', fontSize: 14),
),
),
)
],
),
),
],
),
),
),
);
screenshot of error
You need to declare the provider in you main material widget. Atm you are using it but you haven't told flutter that you will use it.
https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#changenotifierprovider

Flutter GridView is not scrolling

I am adding a header in the grid view. The header is scrolling but when touching grid view. It is not scrolling. I want to scroll header and gridview.
I have used SingleChildScrollView and Expanded. How to solve the please help me.
My code is shown below
Widget ItemGridview() {
return Container(
color: Colors.white,
padding: EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Expanded(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
new Text(
'Items of products',
style: TextStyle(fontWeight: FontWeight.w700, fontSize: 18.0),
textAlign: TextAlign.left,
),
GridView.count(
shrinkWrap: true,
primary: true,
padding: EdgeInsets.only(top:15.0),
crossAxisCount: 3,
childAspectRatio: 0.60, //1.0
mainAxisSpacing: 0.2, //1.0
crossAxisSpacing: 4.0, //1.0
children: createCategoryList(),
),
],
),
)
)
]
),
);
}
In my code Items of products is the header.
List<Widget> createCategoryList() {
List<Widget> createCategoryList = List<Widget>();
for (int i = 0; i < documents.length; i++) {
createCategoryList
.add(makeGridCell(documents[i].data['title'], "name", 8,documents[i].data['id']));
}
return createCategoryList;
}
Container makeGridCell(String name, String image, int count, String id) {
return Container(
child: new GestureDetector(
onTap: () {
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
verticalDirection: VerticalDirection.down,
children: <Widget>[
new Container(
child: Image.asset('assets/' + image + ".jpg"),
),
new Container(
color: Colors.white,
padding: EdgeInsets.only(left: 5),
child: new Text(name,
style: TextStyle(
fontWeight: FontWeight.w500, fontSize: 18.0)),
),
],
),
));
}
The createCategoryList() is the list of items in grid written in widget.
I had similar widget tree like you
a gridview.count() wrapped in SingleChildScrollView adding
physics: ScrollPhysics(),
to GridView.count() Widget Solved my problem
source:https://github.com/flutter/flutter/issues/19205
Add physics: ScrollPhysics() property to Gridview. it iwll scroll.
just add some property in GridView
Widget _buildFields(BuildContext context) {
return Container(
color: Colors.white,
child: GridView.count(
crossAxisCount: 2,
crossAxisSpacing: 2.0,
mainAxisSpacing: 2.0,
shrinkWrap: true,
scrollDirection: Axis.vertical,
physics: NeverScrollableScrollPhysics(),
children: List.generate(choices.length, (index) {
return Center(
child: new Column(
children: [
new Expanded(
child: SelectCard(choice: choices[index]),//your card wight
),
],
),
);
}),
));
}
and use like this
class _Dashboard extends State<Dashboard> {
#override
Widget build(BuildContext context) {
return OrientationBuilder(builder: (context, orientation) {
return ListView(
children: <Widget>[
Container(
height: 200,
child: Image.network(
"https://www.gizbot.com/img/2013/11/23-weekend-deals-top-10-latest-smartphones.jpg"),
),
_buildFields(context),
],
);
});
}
}
You have some issues related to the Scroll of your widgets, you can reduce the amount of Widgets using Wrap, like this :
Container(
color: Colors.white,
padding: EdgeInsets.all(10),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'Items of products',
style: TextStyle(fontWeight: FontWeight.w700, fontSize: 18.0),
textAlign: TextAlign.left,
),
Padding(
padding: const EdgeInsets.only(top: 15.0),
child: Wrap(
spacing: 20.0,
alignment: WrapAlignment.spaceEvenly,
children:createCategoryList(),
),
],
),
)
)
]
),
);
Add a constraint width or a fixed with to the widget of your item:
return Container(
constraints:
BoxConstraints(maxWidth: MediaQuery.of(context).size.width / 4),
child: new GestureDetector(
I think you need to use some custom scroll view
CustomScrollView(
primary: false,
slivers: <Widget>[
SliverPadding(
padding: const EdgeInsets.all(20.0),
sliver: SliverGrid.count(
crossAxisSpacing: 10.0,
crossAxisCount: 2,
children: <Widget>[
const Text('He\'d have you all unravel at the'),
const Text('Heed not the rabble'),
const Text('Sound of screams but the'),
const Text('Who scream'),
const Text('Revolution is coming...'),
const Text('Revolution, they...'),
],
),
),
],
)
Just ran into this myself, change your primary parameter for the GridView to false, give that a try.
In Gridview.builder scrolling is not working for smaller resolutions like tablet mode,mobile mode then just wrap the Gridview.builder under the listview.builder widget.
SizedBox(
width: screenSize.width,
height: screenSize.height * entry.contentHeightFactor,
child: ListView.builder(
itemCount: 1,
itemBuilder: (context, index) {
return Card(
child: Container(
width: screenSize.width * 0.8,
height: screenSize.height * 0.72,
padding: const EdgeInsets.all(10),
child: GridView.builder(
scrollDirection: Axis.vertical,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
),
padding: const EdgeInsets.all(5),
itemCount: 30,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child:Card(....),
);
},
),
),
);
},
),
),