I have a CategoryList that I want to return a list of elevated buttons that are built from some JSON data.
The buttons are built however the text does not display inside the buttons. They are drawn in the app when loaded but the text does not appear.
I have tried to modify the style for it but to no avail and I know that the name in print(categories[index].name); is available but it's not being displayed.
The image below illustrates the problem. The top container is a horizontal list of ElevatedButtons but without the text inside displayed. The container beneath that is static to show what is expected.
Has anyone else run into this issue, if so what was your workaround/solution?
class CategoryList extends StatelessWidget {
const CategoryList({Key? key, required this.categories}) : super(key: key);
final List<Category> categories;
#override
Widget build(BuildContext context) {
return GridView.builder(
padding: const EdgeInsets.all(5.0),
scrollDirection: Axis.horizontal,
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200,
childAspectRatio: 3 / 2,
crossAxisSpacing: 20,
mainAxisSpacing: 20),
itemCount: categories.length,
itemBuilder: (context, index) {
return Center(
child: ElevatedButton(
onPressed: () {
print(categories[index].id);
print(categories[index].name);
},
child: Text(categories[index].name,
style: TextStyle(
fontStyle: FontStyle
.normal)),
style: ButtonStyle(
shadowColor: MaterialStateProperty.all<Color>(Colors.black),
backgroundColor:
MaterialStateProperty.all<Color>(Colors.deepPurple),
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
),
),
),
),
);
},
);
}
}
childAspectRatio == 1.5, try to use a bigger value like 10 to see if it changes.
The solution that solved the problem was to use the switch the GridView.Builder for the ListView.builder and then to change the scroll direction to horizontal.
class CategoryList extends StatelessWidget {
const CategoryList({Key? key, required this.categories}) : super(key: key);
final List<Category> categories;
#override
Widget build(BuildContext context) {
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: categories.length,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.only(left: 7, right: 7),
child: ElevatedButton(
onPressed: () {},
child: Text(categories[index]
.name),
style: ButtonStyle(
shadowColor: MaterialStateProperty.all<Color>(Colors.black),
backgroundColor:
MaterialStateProperty.all<Color>(Colors.purple),
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
),
),
),
));
},
);
}
}
Related
I am trying to make UI of calculator based on my drawing,
here I have divided screen in two expanded container, top one for output and bottom one for buttons...
in bottom container I have taken grid view to show all buttons,
I want to fit all button's in bottom area without having scrolling effect of grid view.
in my code...grid view not showing last row...I have to scroll down to view it...
here is my code
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Expanded(child: Container(color: Colors.orange,)),
Expanded(
child: GridView.builder(
itemCount: buttons.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4),
itemBuilder: (context, index) {
return ButtonWidget(color: Colors.grey,
ontap: () {},
caption: buttons[index].toString(),
textcolor: Colors.black);
})),
],
),
),
);
}
and here is button's class
class ButtonWidget extends StatelessWidget {
final color;
final textcolor;
final String caption;
final VoidCallback ontap;
const ButtonWidget(
{Key? key,
required this.color,
required this.ontap,
required this.caption,
required this.textcolor})
: super(key: key);
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
color: Colors.grey[400],
borderRadius: BorderRadius.circular(100),
),
child: Center(
child: Text(
caption.toString(),
style: GoogleFonts.actor(fontSize: 30,fontWeight: FontWeight.bold),
)),
),
);
}
}
1.Remove your Expanded for GridView.
Disable scrolling for GridView.
Like this.
GridView.builder(
/// Add these two lines
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
/// Your code,
),
Tip:
If you don't wanna have small container on top, you can resize buttons' aspect ratio like this. But it will make buttons look a bit ugly.
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
///Add this, tweak the value as you wish
childAspectRatio: 1.3,
),
Have Fun!
I have a list of the button in my flutter app like the picture :enter image description here
and I need to select the container who I'm click on it
for example, change the container color
you can use container or button and GestureDetector like below example
import 'package:flutter/material.dart';
class SelectableGridView extends StatefulWidget {
const SelectableGridView({Key? key}) : super(key: key);
#override
State<SelectableGridView> createState() => _SelectableGridViewState();
}
class _SelectableGridViewState extends State<SelectableGridView> {
int selectedIndex = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blueGrey,
body: Padding(
padding: const EdgeInsets.all(16.0),
child: GridView.builder(
physics: const ClampingScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 16.0,
mainAxisSpacing: 16.0,
),
itemCount: 18,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () => setState(() {
selectedIndex = index;
}),
child: Container(
color: selectedIndex == index ? Colors.pink : Colors.white,
),
);
},
),
),
);
}
}
TBH I'm not sure what your asking exactly, but this may or may not help you:
GestureDetector
This will let you respond to clicks on whatever it surrounds, so for example
return
GestureDetector(
onTap: (){
//Do something here to respond to a tap on the child Container()
},
child: Container(...) /// Your box
Now you can do something with it.
Hope this is what you were asking about
You can also use InkWell in this following way,
First you have to declare Color in your instances and after that you can use it in your onPress() widget.
Color _colorContainer = Colors.blue;
Now you can use it in your widget as follow:
Ink(
child: InkWell(
child: Container(
width: 200,
height: 200,
color: _colorContainer ,
),
onTap: () {
setState(() {
_colorContainer = _colorContainer == Colors.red ?
Colors.blue :
Colors.red;
});
},
)),
I have added a picture of what I plan to implement. It's a group button where you can only select one option at a time. I used a package called "group_button" but it allows multiple selection at a time which isn't what I want.
Recommend an alternative means of achieving this.
Picture of what I plan to implement
Updated 18.02.2022
They removed old constructor GroupButton.radio and GroupButton.checkbox in version 4.4.0 and still don't updated documentation.
Proper solution is set isRadio property of GroupButton to true.
GroupButton(
isRadio: true,
onSelected: (index, isSelected) => print('$index button is selected'),
buttons: ["12:00", "13:00", "14:30", "18:00", "19:00", "21:40"],
)
Old answer:
Never used that package but by looking on they pub.dev page I can see following.
Now you can use even simpler constructors to build your button groups.
Example for a group with a single value selection:
GroupButton.radio(
buttons: ['12:00', '13:00', '14:00'],
onSelected: (i) => debugPrint('Button $i selected'),
)
Link: https://pub.dev/packages/group_button#cant-easier-to-use
A fully working example for this:
class T extends StatefulWidget {
const T({Key? key}) : super(key: key);
#override
_TState createState() => _TState();
}
class _TState extends State<T> {
List<bool> isCardEnabled = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('T'),
),
body: GridView.builder(
padding: const EdgeInsets.all(15),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 3,
crossAxisSpacing: 10,
mainAxisSpacing: 10
),
itemCount: 4,
itemBuilder: (BuildContext context, int index){
isCardEnabled.add(false);
return GestureDetector(
onTap: (){
isCardEnabled.replaceRange(0, isCardEnabled.length, [for(int i = 0; i < isCardEnabled.length; i++)false]);
isCardEnabled[index]=true;
setState(() {});
},
child: SizedBox(
height: 40,
width: 90,
child: Card(
color: isCardEnabled[index]?Colors.cyan:Colors.grey.shade200,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8)
),
child: Center(
child: Text('Ability Tag',
style: TextStyle(
color: isCardEnabled[index]?Colors.white:Colors.grey,
fontSize: 18
),
),
),
),
)
);
}),
);
}
}
I have a list of title which is in text. I can change the color of title which in pressed but all the title's color changes.Can I change the the pressed titles only?
I have stored intial color this way
Color color = Colors.yellow;
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: state.posts.length,
itemExtent: 300.0,
itemBuilder: (context, index) {
final item = state.posts[index];
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10.0, vertical: 6.0),
child: GestureDetector(
onTap: () {
setState(() {
color = Colors.black;
});
},
child: Container(
color: Colors.red,
child: Text(
item.title,
style: TextStyle(color: color),
),
),
),
);
},
),
You can create a list of colors with the same length of your titles, and when you press you can use the same index of the titles to change the color.
/// declare outside build function
List<Color> titleColors = [];
if(colors.isEmpty) {
for(String title in titles) {
colors.add(Colors.yellow);
}
}
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: state.posts.length,
itemExtent: 300.0,
itemBuilder: (context, index) {
final item = state.posts[index];
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10.0, vertical: 6.0),
child: GestureDetector(
onTap: () {
setState(() {
titleColors[index] = Colors.black;
});
},
child: Container(
color: Colors.red,
child: Text(
item.title,
style: TextStyle(color: titleColors[index]),
),
),
),
);
},
),
I can see several solutions for this.you can create a separate stateful widget for this or you can use state management method(like provider).
Issue is here
setState(() {
color = Colors.black;
});
when we click one button the whole list view is rebuild using the colour we given.For that we need to keep the main widget state stable and change the list view child state.
try this.first create a list item stateful widget.
import 'package:flutter/material.dart';
class ListItem extends StatefulWidget {
const ListItem({Key key,}) : super(key: key);
#override
_ListItemState createState() => _ListItemState();
}
class _ListItemState extends State<ListItem> {
Color color = Colors.yellow;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: GestureDetector(
onTap: () {
setState(() {
color = Colors.black;
});
},
child: Container(
color: Colors.red,
child: Text(
item.title,
style: TextStyle(color: color),
),
),
),
);
}
}
then add this to your list view.
ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: state.posts.length,
itemExtent: 300.0,
itemBuilder: (context, index) {
final item = state.posts[index];
return ListItem();
},
);
this will work.You want to pass the item value to that widget.You have to create a constructor variable and pass it to that ListItem widget.
I am an android developer and new to flutter.
I would like to create a GridView with wrap content item height (I draw it with pen in the screenshot). But I have tried with the following code and it gave me only square grid item. I would like how to get height wrap content grid item and I have no idea and can't find how to get it. Please help. Thank you.
class CategoryItem extends StatelessWidget {
final Category category;
CategoryItem({Key key, #required this.category})
: assert(category != null),
super(key: key);
#override
Widget build(BuildContext context) {
return Card(
child: Text(
category.name,
style: TextStyle(fontSize: 34.0, fontWeight: FontWeight.bold),
),
color: Colors.amberAccent,
);
}
}
class CategoryGrid extends StatefulWidget {
final List<Category> items;
const CategoryGrid({Key key, this.items}) : super(key: key);
#override
_CategoryGridState createState() => _CategoryGridState();
}
class _CategoryGridState extends State<CategoryGrid> {
#override
Widget build(BuildContext context) {
final Orientation orientation = MediaQuery.of(context).orientation;
return Column(
children: <Widget>[
Expanded(
child: SafeArea(
top: false,
bottom: false,
child: GridView.builder(
itemCount: widget.items.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: (orientation == Orientation.portrait) ? 2 : 3,),
itemBuilder: (BuildContext context, int index) {
return CategoryItem(category: widget.items[index],);
},
),
),
),
],
);
}
}
For height you can use "childAspectRatio"
For example-
GridView.count(
childAspectRatio: 4.0,
crossAxisCount: 2,
padding: EdgeInsets.all(5.0),
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0),
child: Text(
'10:00 AM - 12:00 PM',
style: new TextStyle( color: Colors.black87, fontSize: 14.0,
fontWeight: FontWeight.normal,
),
),
);
],
shrinkWrap: true,
// todo comment this out and check the result
physics: ClampingScrollPhysics(),
)
To wrap content grid item you can use the childAspectRatio property of gridview
Ex.
GridView.builder(
itemCount: widget.items.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: (orientation == Orientation.portrait) ? 2 : 3, childAspectRatio:(MediaQuery.of(context).size.height * 0.006)),
itemBuilder: (BuildContext context, int index) {
return CategoryItem(category: widget.items[index],);
},
)
you can set childAspectRatio 0.006 instead of according to your content size
You need to set childAspectRatio attribute of SliverGridDelegateWithFixedCrossAxisCount delegate to control the height with respect to width of the grid item.
If you just want to "shrink" the height (and something like match_parent for widhth) of the text widget wrap it around a Column, Row and Expanded like this
class CategoryItem extends StatelessWidget {
final Category category;
CategoryItem({Key key, #required this.category})
: assert(category != null),
super(key: key);
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Card(
child: Text(
category.name,
style: TextStyle(fontSize: 34.0, fontWeight: FontWeight.bold),
),
color: Colors.amberAccent,
),
),
],
),
],
);
}
}
In GridView use this line
the childAspectRatio as per yor need
childAspectRatio: double,