Problem adding widget to GridView with button and scroll - flutter

At first I had a Wrap that by clicking on the "add" button would add a new card to the Wrap. Then I changed the Wrap to GridView so that I could add scrolling. However, now when I press the button nothing shows on the device, but if I change GridView back to a Wrap and hot reload, the cards show up? I'm not sure what's wrong.
Also I can't scroll, I know I'm doing something wrong, but I have no idea what.
class MainScreen extends StatefulWidget {
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
List<Widget> cards = [];
dynamic addReusableCard (String activity, int goal, double elapsed){
return cards.add(ReusableCard(activityText: activity, activityLength: goal, activityTimeElapsed: elapsed,));
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Text('TIME CARDS',
style: TextStyle(
fontSize: 20.0,
letterSpacing: 5.0,
),),
Text('You\'re awake for a total of 16h',
style: TextStyle(
fontSize: 16.0,
fontStyle: FontStyle.italic,
),),
Expanded(
flex: 9,
child: GridView.count(
crossAxisCount: 2,
childAspectRatio: (175.0 / 220.0),
scrollDirection: Axis.vertical,
shrinkWrap: true,
physics: ScrollPhysics(),
children: cards
),
),
Padding(
padding: const EdgeInsets.all(18.0),
child: Align(
alignment: Alignment.bottomRight,
child: FloatingActionButton(
onPressed: (){
setState(() {
addReusableCard('reading', 2, 0.3);
});
},
backgroundColor: kAccentColor,
elevation: 0.0,
child: Icon(Icons.add),
),
),
),
],
),
),
),
);
}
}
Thanks in advance

For a dynamic list length you should use gridView.builder()
Here is the relevant code:
Expanded(
flex: 9,
child: GridView.builder(
itemCount: cards.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2
),
itemBuilder: (BuildContext context, int index) {
return cards[index];
}
)
),

Related

When I use GridView widgets as a children of ListView, the scroll control is active for the ListView rendered area only & not from the GridView area

5. I am having an issue with scrolling. The outer container ListView
is scrolling fine, but when I grab the gridView elements the scroll effect doesn't work. What is it that I am missing here? (GIF below)
HomeScreen() has HomeBody() widget; HomeBody() has ListView, whose children are BuildSectionContainers() which have a services widgets as child.
class HomeScreem extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Stethoscope',
style: TextStyle(
color: Theme.of(context).accentColor,
fontSize: 24,
fontFamily: GoogleFonts.pacifico().fontFamily,
letterSpacing: 1.5),
),
centerTitle: true,
),
// APP BODY
body: HomeBody(),
);
}
}
class HomeBody extends StatelessWidget {
#override
Widget build(BuildContext context) {
final healthService = Provider.of<HealthServices>(context);
final service = healthService.services;
return ListView(
children: [
//
BuildSectionContainer(
healthService: healthService,
service: service,
sectionTitle: 'SERVICES',
child: Container(
height: 245,
child: BuildGeneralServicesGrid(
healthService: healthService,
service: service,
),
),
),
//
BuildSectionContainer(
healthService: healthService,
service: service,
sectionTitle: 'EMERGENCY SERVICES',
child: Container(
height: 245,
child: BuildEmergencyServicesGrid(
healthService: healthService,
service: service,
),
),
),
],
);
}
}
class BuildEmergencyServicesGrid extends StatelessWidget {
const BuildEmergencyServicesGrid({
Key? key,
required this.healthService,
required this.service,
}) : super(key: key);
final HealthServices healthService;
final List<HealthService> service;
#override
Widget build(BuildContext context) {
return GridView.builder(
itemCount: healthService.services.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 1,
mainAxisSpacing: 1,
mainAxisExtent: 120,
),
itemBuilder: (context, index) => GestureDetector(
child: Card(
color: Theme.of(context).primaryColor.withOpacity(0.1),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.all(8.0),
child: service[index].icon,
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
service[index].serviceName,
style: Theme.of(context).textTheme.bodyText2,
textAlign: TextAlign.center,
),
),
],
),
),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => AudioConsultation(),
));
},
),
);
}
}
The issue happens because, the gridview interferes with the listview scrolling. You can set the physics property of your Gridview to NeverScrollableScrollPhysics to fix the issue.
GridView.builder(
// Disable scrolling for grid
physics: NeverScrollableScrollPhysics(),
// Your remaining code
),

Flutter Button Placed below GridView Builder

I want to have a big long button below the Gridview just like the logout button in the Roblox app
I manage to create a gridview and button using the Column , however the button is floating above the gridview, how to make it placed nicely below the gridview without floating above the gridview?
Here is my code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final title = 'Grid List';
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: MainMenuBody(),
),
);
}
}
class MainMenuBody extends StatelessWidget {
#override
Widget build(BuildContext context) {
final List<MenuData> menu = [
MenuData(Icons.move_to_inbox_outlined, 'Menu 1'),
MenuData(Icons.find_in_page_outlined, 'Menu 2'),
MenuData(Icons.find_in_page_outlined, 'Menu 3'),
MenuData(Icons.upgrade_outlined, 'Menu 4'),
MenuData(Icons.upgrade_outlined, 'Menu 5'),
MenuData(Icons.play_for_work_outlined, 'Menu 6'),
MenuData(Icons.play_for_work_outlined, 'Menu 7'),
MenuData(Icons.assignment_turned_in_outlined, 'Menu 8'),
MenuData(Icons.assignment_turned_in_outlined, 'Menu 9'),
MenuData(Icons.fact_check_outlined, 'Menu 10')
];
return Container(
child: Scrollbar(
thickness: 3,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10.0),
child: SingleChildScrollView(
child: Column(
children: [
GridView.builder(
shrinkWrap: true,
physics: BouncingScrollPhysics(),
itemCount: menu.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
childAspectRatio: 1,
crossAxisCount: 2,
crossAxisSpacing: 4.0,
mainAxisSpacing: 4.0),
itemBuilder: (BuildContext context, int index) {
return Card(
elevation: 0.2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0)),
child: InkWell(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Icon(
menu[index].icon,
size: 30,
),
SizedBox(height: 20),
Text(
menu[index].title,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 10,
color: Colors.black87),
)
],
),
),
);
},
),
Center(
child: RaisedButton(
child: Text("Button"),
onPressed: (){},
),
),
],
),
),
),
));
}
}
class MenuData {
MenuData(this.icon, this.title);
final IconData icon;
final String title;
}
I have modified your code a little bit. Please have a look.
Wrap the column inside a SingleChildScrollView, Remove Expanded widget and add shrinkWrap: true inside GridView
return Container(
child: Scrollbar(
thickness: 3,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10.0),
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Column(
children: [
GridView.builder(
shrinkWrap: true,
physics: BouncingScrollPhysics(),
itemCount: menu.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
childAspectRatio: 1,
crossAxisCount: 2,
crossAxisSpacing: 4.0,
mainAxisSpacing: 4.0),
itemBuilder: (BuildContext context, int index) {
return Card(
elevation: 0.2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0)),
child: InkWell(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Icon(
menu[index].icon,
size: 30,
),
SizedBox(height: 20),
Text(
menu[index].title,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 10,
color: Colors.black87),
)
],
),
),
);
},
),
Center(
child: RaisedButton(
child: Text("Button"),
onPressed: (){},
),
),
],
),
),
),
));
Update: Not sure if this is in general the way to go, but you could create a scrollview wrapping the column wrapping gridview and the button. In grid view you then have to disable scrolling with physics: new NeverScrollableScrollPhysics().
But maybe columns and rows are the way to go for this

Flutter: Scroll view not responding

I am pretty new to flutter. I have build a landing page using grid view and added a bottom navigation bar. The navigation bar is called first after login in and I have added the screen to the navigation class. The issue am facing is that the navigation bar is on top of my grid items, when I try to scroll up, the grid items are sticky and not moving, what am I not doing right??
my home screen code
class GridDashboard extends StatelessWidget {
var services = [
"Home",
"Update",
"Bluetooth",
"Forms",
"Supervisor",
"Messages",
"Settings",
"App updates",
"Logout",
];
var images = [
"assets/home.png",
"assets/updated.png",
"assets/bluetooth.png",
"assets/todo.png",
"assets/supervisor.png",
"assets/message.png",
"assets/setting.png",
"assets/update.ico",
"assets/logout.png",
];
#override
Widget build(BuildContext context) {
List<Items> myList = [home, update, bluetooth, forms, supervisor, messages, settings, check, logout];
var color = 0xff453658;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 500,
// margin: EdgeInsets.only(top: 10),
// padding: EdgeInsets.all(20),
child: GridView.builder(
// add this
shrinkWrap: true,
itemCount: services.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: MediaQuery.of(context).size.width /
(MediaQuery.of(context).size.height / 1.4),
),
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
Navigator.push(context, new MaterialPageRoute<Widget>(
builder: (BuildContext context) {
if(myList != null){
return myList[index].screen;
}else{
return null;
}
}));
},
child: Padding(
padding: EdgeInsets.all(3),
child: Card(
elevation: 10,
child: ListView(
children: <Widget>[
SizedBox(
height: 20,
),
Image.asset(
images[index],
height: 50.0,
width: 50.0,
),
Padding(
padding: const EdgeInsets.all(20.0),
child: Text(
services[index],
style: TextStyle(
fontSize: 16.0,
height: 1.2,
color: Colors.white,
fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
],
),
color: Color(color),
),
),
);
},
),
),
);
}
}
class Items {
String title;
String subtitle;
String event;
String img;
final Widget screen;
Items({this.title, this.subtitle, this.event, this.img, this.screen});
}
my Nav bar code
class _NavSCreenState extends State<NavSCreen> {
final List<Widget> _screens = [Home()];
final List<IconData> _icons = const [
Icons.home,
Icons.settings,
MdiIcons.accountCircleOutline,
MdiIcons.accountGroupOutline,
Icons.menu,
];
int _selectedIndex = 0;
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: _icons.length,
child: Scaffold(
body: IndexedStack(index: _selectedIndex, children: _screens),
bottomNavigationBar: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: CustomTabBar(
icons: _icons,
selectedIndex: _selectedIndex,
onTap: (index) => setState(() => _selectedIndex = index),
),
),
));
}
}
Try this by adding SingleChildScrollView. Hope this will solve your problem.
#override
Widget build(BuildContext context) {
List<Items> myList = [home, update, bluetooth, forms, supervisor, messages, settings, check, logout];
var color = 0xff453658;
return Scaffold(
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 500,
// margin: EdgeInsets.only(top: 10),
// padding: EdgeInsets.all(20),
child: GridView.builder(
// add this
shrinkWrap: true,
itemCount: services.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: MediaQuery.of(context).size.width /
(MediaQuery.of(context).size.height / 1.4),
),
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
Navigator.push(context, new MaterialPageRoute<Widget>(
builder: (BuildContext context) {
if(myList != null){
return myList[index].screen;
}else{
return null;
}
}));
},
child: Padding(
padding: EdgeInsets.all(3),
child: Card(
elevation: 10,
child: ListView(
children: <Widget>[
SizedBox(
height: 20,
),
Image.asset(
images[index],
height: 50.0,
width: 50.0,
),
Padding(
padding: const EdgeInsets.all(20.0),
child: Text(
services[index],
style: TextStyle(
fontSize: 16.0,
height: 1.2,
color: Colors.white,
fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
],
),
color: Color(color),
),
),
);
},
),
),
),
),
);
}
You need to embed the GridView into a SingleChildScrollView widget. This widget handles the scrolling for its child, which is in your case the GridView. The same applies to ListView.
See the links for detailed documentation.
// ...
child: Container(
height: 500,
child: SingleChildScrollView(
child: GridView.builder(
// ...
)
)
)
// ...
EDIT
I forgot, that you have to give a GridView a height to work inside a SingleChildScrollView. You can use a Container that wraps the GridView.
// ...
child: Container(
height: 500,
child: SingleChildScrollView(
child: Container(
height: 500,
child: GridView.builder(
// ...
)
)
)
)
// ...
But with that approach you have to give your GridView a predefined height. An alternative is the CustomScrollView but you have to use a SliverGrid for that.
CustomScrollView(
slivers: [
SliverGrid(
// ...
)
]
)

Exception caught by widgets library A build function returned null

I am fairly new to flutter development. I am trying to have static header and grid card items that scroll underneath the static header, but I end up getting the error. I have tried to research no success. What am i doing wrong?
Exception caught by widgets library A build function returned null.
The relevant error-causing widget was: GridDashboard
and
A RenderFlex overflowed by 99515 pixels on the bottom. The relevant
error-causing widget was: Column
my griddashboard class
class GridDashboard extends StatelessWidget {
var services = [
"Home",
"Settings",
"Supervisor",
"Logout",
"Forms",
"Messages",
"bluetooth",
"Check for updates",
"Update"
];
var images = [
"images/calendar.png",
"images/festival.png",
"images/food.png",
"images/image.png",
"images/logout.png",
"images/setting.png",
"images/note.png",
"images/todo.png",
"images/map.png",
];
#override
Widget build(BuildContext context) {
// return Padding(
// padding: const EdgeInsets.all(8.0),
// child:
GridView.builder(
itemCount: services.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: MediaQuery.of(context).size.width/(MediaQuery.of(context).size.height/1.4)
),
itemBuilder: (BuildContext context, int index){
return Card(
child: Column(
children: <Widget>[
SizedBox(
height: 20,
),
Image.asset(images[index], height: 50.0, width: 50.0,),
Padding(
padding: const EdgeInsets.all(20.0),
child: Text(services[index], style: TextStyle(fontSize: 16.0, height: 1.2),textAlign: TextAlign.center ,),
)
],
),
);
},
// ),
);
}
}
my home class
class Home extends StatefulWidget {
#override
HomeState createState() => new HomeState();
}
class HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xff392850),
body: Column(
children: <Widget>[
SizedBox(
height: 110,
),
Padding(
padding: EdgeInsets.only(left: 16, right: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Full Names",
style: GoogleFonts.openSans(
textStyle: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold)),
),
SizedBox(
height: 4,
),
Text(
"Home",
style: GoogleFonts.openSans(
textStyle: TextStyle(
color: Color(0xffa29aac),
fontSize: 14,
fontWeight: FontWeight.w600)),
),
],
),
IconButton(
alignment: Alignment.topRight,
icon: Image.asset(
"assets/notification.png",
width: 24,
),onPressed: ()=>{
},
),
],
),
),
SizedBox(
height: 40,
),
GridDashboard()
],
),
);
}
}
You removed the return keyword from your build function, probably by accident.
GridView.builder(
needs to be
return GridView.builder(
Otherwise your build function returns nothing and you get the errors you are getting now.
as it says your build function was called on null which means you forgot write return out;
your problem is in griddashboard class where you wrote this
Widget build(BuildContext context) {
// return Padding(
// padding: const EdgeInsets.all(8.0),
// child:
GridView.builder(
itemCount: services.length
every time you don't write return in a function it shows that error , not only the build function , so you can handle it by writing return like this
Widget build(BuildContext context) {
return GridView.builder(
itemCount: services.length

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(....),
);
},
),
),
);
},
),
),