I have data that comes from API and I want to arrange it in the form of a table as in the image attached below, but when I do that the data is repeated and I could not solve the problem, I need help on modifying the code below so that I do not want to repeat the code until the modification begins.
Clarification
The code
class StarringComponent extends StatelessWidget {
StarringComponent({Key? key}) : super(key: key);
final List<_StarringModel> _listOfStarring = [
_StarringModel('Michael J. Fox', 'https://www.biography.com/.image/ar_8:10%2Cc_fill%2Ccs_srgb%2Cfl_progressive%2Cg_faces:center%2Cq_auto:good%2Cw_620/MTkwNTAwODA4ODM0NDI2Nzc4/gettyimages-1144626740.jpg'),
_StarringModel('Christopher Lloyd', 'https://s3.r29static.com/bin/entry/9e6/0,0,2000,2000/x,80/2172764/image.jpg'),
_StarringModel('Robert Zimek', 'https://media1.popsugar-assets.com/files/thumbor/XS_IeHJo2d3MzS-0CXmqOZ0Zl34/fit-in/2048xorig/filters:format_auto-!!-:strip_icc-!!-/2019/01/08/515/n/1922398/7f748b5fb07a03fd_GettyImages-1019711520/i/Charlie-Hunnam.jpg'),
_StarringModel('Lea Thompson', 'https://www.independent.ie/migration_catalog/8bb89/25195674.ece/AUTOCROP/w620/N0217211295348219998A_1'),
];
#override
Widget build(BuildContext context) {
return Table(children: List.generate(_listOfStarring.length, (index) => _buildTableRow(context, _listOfStarring[index].name, _listOfStarring[index].image)));
}
TableRow _buildTableRow(BuildContext context, String name, String image) {
return TableRow(
children: List.generate(2, (index) => Padding(
padding: EdgeInsets.symmetric(vertical: 10),
child: Row(
children: [
CircleAvatar(
radius: 14,
backgroundColor: Colors.red.withOpacity(0.4),
backgroundImage: NetworkImage(image),
),
SizedBox(width: 10),
Flexible(
child: Text(name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
))
);
}
}
Starring model
class _StarringModel {
String name, image;
_StarringModel(this.name, this.image);
}
Use GridView for simpler implementation.
GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
...
),
itemCount: _listOfStarring.length,
itemBuilder: (BuildContext ctx, index) {
return _buildItem(
_listOfStarring[index].name,
_listOfStarring[index].image,
);
},
);
Widget _buildItem(String name, String image) {
...
}
Related
I have a create so simple slidable view pager with CarouselSlider:
return Scaffold(
body: CarouselSlider(
options: CarouselOptions(
viewportFraction: 1,
// aspectRatio: 1,
height: double.maxFinite,
// enlargeCenterPage: true,
),
items: List.generate(
10,
(i) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Container(
color: (i % 2 == 0) ? Colors.red : Colors.green,
),
),
Text('text $i', style: TextStyle(fontSize: 16.0)),
],
)),
));
This is its result:
But as you can see next container connects to the first widget, I want when the first widget to be swapped to the left, the next widget appears under the first widget Not next to it. It looks like the following widget is fixed and we remove the top widget.
You can use a package called stacked_page_view, it is very simple, lightweight, and similar to the same original PageView in usage.
Example Snippet:
PageView.builder(
itemCount: 10,
scrollDirection: Axis.vertical,
controller: pageController,
itemBuilder: (context, index) {
return StackPageView(
controller: pageController,
index: index,
child: Container(
color: (colors..shuffle()).first,
child: Center(
child: Text(
'$index',
style: TextStyle(
color: Colors.white,
fontSize: 25,
),
),
),
),
);
},
)
Note: You can control the scroll axis with the property scrollDirection inside PageView.builder() with values of Axis.vertical or Axis.horizontal.
I finally find a way to create stack page view, This is a full codes:
import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter/material.dart';
import 'dummy_data.dart';
import 'page_view_item.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
/// The current page of the page view
double _page = 0;
/// The index of the leftmost element of the list to be displayed
int get _firstItemIndex => _page.toInt();
/// Controller to get the current position of the page view
final _controller = PageController(
viewportFraction: 0.5,
);
/// The width of a single item
late final _itemWidth =
MediaQuery.of(context).size.width * _controller.viewportFraction;
#override
void initState() {
super.initState();
_controller.addListener(() => setState(() {
_page = _controller.page!;
}));
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("LV Scroll"),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
children: [
Positioned.fill(
child: Align(
alignment: Alignment.centerLeft,
child: SizedBox(
width: _itemWidth,
child: FractionallySizedBox(
child: PageViewItem(
index: _firstItemIndex,
width: _itemWidth,
url: model[_firstItemIndex],
),
),
),
),
),
SizedBox(
height: 250,
child: PageView.builder(
padEnds: false,
controller: _controller,
itemBuilder: (context, index) {
return Opacity(
opacity: index <= _firstItemIndex ? 0 : 1,
child: PageViewItem(
index: index,
width: _itemWidth,
url: model[index],
),
);
},
itemCount: model.length,
),
),
],
),
],
),
);
}
}
it's result :
and its reference;
You can use a package called expandable_page_view, it is a PageView widget adjusting its height to currently displayed page. It accepts the same parameters as classic PageView.
ExpandablePageView.builder(
itemCount: 3,
itemBuilder: (context, index) {
return Container(color: Colors.blue);
},
),
I am using GridView to show a different students on screen. I am using my custom made cards to show a student. Now, if the name of a student is very large, it is taking more space and rest of the cards are remaining of same size.
At first, when the name was too large, I was getting an error for less space. Then to fix that, I changed aspect ratio. But now, my screen seems too ditorted. Can you please help me out on how to fix this?
Here are the code snippets -
First, my card -
class CardItem extends StatelessWidget {
final Widget imageUrl;
final String title;
final VoidCallback function;
final BoxDecoration? bor;
final String? board;
final String? standard;
const CardItem({
Key? key,
required this.imageUrl,
required this.title,
required this.function,
this.bor,
this.board,
this.standard
})
: super(key: key);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: function,
child: Column(
children: [
Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
color: cardColor,
child: Container(
padding: EdgeInsets.all(getProportionateScreenHeight(22)),
decoration: bor,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircleAvatar(
radius: 50.0,
child: imageUrl,
),
SizedBox(
height: getProportionateScreenHeight(11),
),
Text(
title,
style: Theme.of(context)
.textTheme
.bodyText2!
.apply(color: Colors.white),
),
Padding(
padding: const EdgeInsets.only(top: 7.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
board??"",
style: TextStyle(
color: brandPurple,
fontSize: 13,
),
),
Text(
standard??"",
style: TextStyle(
color: brandPurple,
fontSize: 13,
),
),
],
),
),
],
),
),
),
],
),
);
}
}
How I used them in GridView -
child: GridView.count(
physics: ScrollPhysics(),
crossAxisSpacing:
getProportionateScreenWidth(25.0),
mainAxisSpacing:
getProportionateScreenHeight(0.0),
childAspectRatio: 2 / 3,
shrinkWrap: false,
crossAxisCount: 2,
children: [
for (int i = 0; i < dataList.length; i++)
CardItem(
imageUrl: dataList[i].avtar == null
? Image.asset(
'assets/images/profile_pic.png')
: CachedNetworkImage(
imageUrl: dataList[i].avtar!,
imageBuilder:
(context, imageProvider) =>
Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: imageProvider,
fit: BoxFit.cover),
),
),
placeholder: (context, url) =>
CircularProgressIndicator(),
errorWidget:
(context, url, error) =>
Icon(Icons.error),
// httpHeaders: {
// "Authorization":
// 'JWT ' + token,
// },
),
title: dataList[i].name!,
board: getBoard(
dataList[i].student_current_board),
standard: getGrade(
dataList[i].student_current_board,
dataList[i].grade),
function: () {
setState(() {
selected_id = dataList[i].id!;
print(dataList[i].name);
Provider.of<APIData>(context,
listen: false)
.initializeCurrentStudent(
dataList[i]);
});
},
bor: selected_id == dataList[i].id!
? border_light()
: BoxDecoration(),
),
Add(
imageUrl:
'assets/images/add_profile_icon.svg',
title: 'Add Profile',
function: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddProf()),
).then((value) => refresh());
},
),
],
),
Here is the UI that I am getting -
You can use
childAspectRatio: 0.75,
It will fix the height / width for all items.
Check the below code for example
class ItemCardGridView extends StatelessWidget {
const ItemCardGridView(
{Key? key,
required this.crossAxisCount,
required this.padding,
required this.items})
// we plan to use this with 1 or 2 columns only
: assert(crossAxisCount == 1 || crossAxisCount == 2),
super(key: key);
final int crossAxisCount;
final EdgeInsets padding;
// list representing the data for all items
final List<ItemCardData> items;
#override
Widget build(BuildContext context) {
return GridView.builder(
padding: padding,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
mainAxisSpacing: 40,
crossAxisSpacing: 24,
// width / height: fixed for *all* items
childAspectRatio: 0.75,
),
// return a custom ItemCard
itemBuilder: (context, i) => ItemCard(data: items[i]),
itemCount: items.length,
);
}
}
I think you can use the following package for equal and beautiful gridviews.
Here's the link: https://pub.dev/packages/flutter_staggered_grid_view
In this package you can use Masonry Gridview which will surely help you!
I am trying to create some ocassion cards inside a pageview and was wondering if there was a way to make my fontsize dynamic to avoid pixel overflow. Here is a screenshot of a card that works fine:
But when I add an occasion that has more characters...
Here is my code:
class Category {
String name;
IconData icon;
Widget route;
Category(this.name, this.icon, this.route);
}
class CalendarEvents {
String title;
String date;
CalendarEvents(this.title, this.date);
}
class AccountPage extends StatefulWidget {
#override
_AccountPageState createState() => _AccountPageState();
}
class _AccountPageState extends State<AccountPage> {
List<Category> _categories = [
Category('My History', Icons.history, MyHistory()),
Category('Dates to Remember', Icons.event_note, DatesToRemember()),
Category('Terms and Conditions', Icons.assignment, TermsandConditions()),
Category('Privacy Notice', Icons.security, PrivacyNotice()),
Category('Rate us' , Icons.stars, RateUs()),
Category('Send us Feedback' , Icons.feedback, GiveUsFeedback())
];
DateFormat formatter = DateFormat('dd/MM/yyyy');
List<CalendarEvents> _events = [
CalendarEvents('Christmas Day', "25/12/2020"),
CalendarEvents('New Years Eve', "31/12/2020"),
CalendarEvents('New Years Day',"01/01/2021"),
CalendarEvents('Valentines Day', "14/02/2021"),
CalendarEvents('A very long occasion that needs to be resized','01/01/2021')
];
int _index = 0;
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
Container(
child: SizedBox(
height: 75, // card height
child: PageView.builder(
itemCount: _events.length,
controller: PageController(viewportFraction: 0.5),
onPageChanged: (int index) => setState(() => _index = index),
itemBuilder: (_, i) {
return Transform.scale(
scale: i == _index ? 1 : 0.5,
child: Card(
elevation: 6,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(formatter.parse(_events[i].date).day.toString()),
Text(DateFormat.MMMM().format(formatter.parse(_events[i].date)).toString()),
Text(
_events[i].title,
style: AppBarTextStyle,
),
],
),
),
);
},
),
),
),
// SizedBox(height: 100.0,),
Container(
height: MediaQuery.of(context).size.height * 0.7,
child: ListView.builder(
itemCount: _categories.length,
itemBuilder: (context, index) {
return Column(
children: <Widget>[
ListTile(
leading: Icon(_categories[index].icon, color: Colors.black,),
title: Text(_categories[index].name),
trailing: Icon(Icons.arrow_forward_ios),
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => _categories[index].route)),
),
Divider(), //
],
);
}),
),
],
),
);
}
}
It would be useful to resize the font depending on the length of occasion. If this is possible, what would be the best way of achieving these results? Thanks
If you want control over the fontsize even after resized, you should use https://pub.dev/packages/auto_size_text package like #Abhishek mentioned
If you just want the text to resize freely, you can use FittedBox and wrap it around Text widget, like this:
FittedBox(
fit: BoxFit.contain,
child: Text()
)
you can use https://pub.dev/packages/auto_size_text package like
title: Text(_categories[index].name),
instead of this
title: AutoSizeText(
_categories[index].name,
minFontSize: 10,
stepGranularity: 10,
maxLines: 4,
overflow: TextOverflow.ellipsis,
)
I'm trying to make a grid of products using GridView.Builder but it gives error :
Vertical viewport was given unbounded height.
I tried to use flexible on GridView it worked but I need to use GridView.Builder Specifically
and if I tried to wrap it with Flexible or specific height container it doesn't scroll ,any tips?
import 'package:flutter/material.dart';
class Products extends StatefulWidget {
#override
_ProductsState createState() => _ProductsState();
}
class _ProductsState extends State<Products> {
var productList=[
{
"name":"Blazer",
"picture":"images/products/blazer1.jpeg",
"oldPrice":120,
"price":100
},
{
"name":"Dress",
"picture":"images/products/dress1.jpeg",
"oldPrice":120,
"price":100
},
{
"name":"hills",
"picture":"images/products/hills1.jpeg",
"oldPrice":11,
"price":10
},
{
"name":"pants",
"picture":"images/products/pants2.jpeg",
"oldPrice":12,
"price":200,
}
];
#override
Widget build(BuildContext context) {
return GridView.builder(
scrollDirection: Axis.vertical,
itemCount: productList.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemBuilder: (context,index){
return SingalProduct(
name: productList[index]['name'],
picture: productList[index]['picture'],
oldPrice: productList[index]['oldPrice'],
price: productList[index]['price'],
);
},
);
}
}
class SingalProduct extends StatelessWidget {
final name,picture,oldPrice,price;
SingalProduct({this.name,this.picture,this.oldPrice,this.price});
#override
Widget build(BuildContext context) {
return Card(
child: Hero(
tag: name,
child: InkWell(
onTap: (){},
child: GridTile(
footer: Container(
height: 40,
color: Colors.white,
child: Padding(
padding: EdgeInsets.fromLTRB(8, 12, 0, 0),
child: Text(name,textAlign: TextAlign.start,style: TextStyle(fontWeight: FontWeight.bold,fontSize: 16),),
),
),
child: Image.asset(picture,fit: BoxFit.cover, ),
),
),
),
);
}
}
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,