I have a gridView(3 items in a row) with dynamic number of items. I want gridView item should be at bottom means if there are 3 items then one row at bottom of screen, if there are 6 items then two row at bottom. So a dynamic padding at top depending on item count and screen size. My code structure is like below
class className extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: [
ImageFiltered(
//code here
),
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.black38,
),
GridView.builder(
primary: false,
reverse: false,
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 30,
),
itemBuilder: (context, index) {
return InkWell(
onTap: () {
//code
},
child: CustomWidget(
title: toolkitStore.getLabel(toolKit),
icon: ImageIcon(
AssetImage(
'assets/images/abcd.png'),
size: 48,
color: kWhiteColor,
),
),
);
},
itemCount: getCount().length,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
),
],
),
),
);
}
}
Now I have this
but I want this
Thanks in advance.
**Try this one: **
import 'package:flutter/material.dart';
class ClassName extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: [
Container(height: 100,width: 200,color: Colors.green,),//<----Your any widget
Align(
alignment: Alignment.bottomCenter,
child: GridView.builder(
primary: false,
reverse: true,
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 30,
),
itemBuilder: (context, index) {
return InkWell(
onTap: () {
//code
},
child: const Icon(Icons.person,size: 50,color: Colors.green,),
);
},
itemCount: 5,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
),
),
Container(height: 100,width: 100,color: Colors.red,),//<----Your any widget
],
),
),
);
}
}
Wrap your GridView.builder with Align widget provide alignment: Alignment.bottomCenter,
Align(
alignment: Alignment.bottomCenter,
child: GridView.builder(
primary: false,
reverse: false,
While using Stack use positional widget(Positioned, Align,...) to place children on UI.
Thank you, everyone.
I solved my problem by using Positioned widget and setting shrinkWrap: true, my code structure is
new Positioned(
left: 0.0,
bottom: 0.0,
width: MediaQuery.of(context).size.width,
child: GridView.builder(
shrinkWrap: true, //this is most important
))
Related
Place an arrow at the end of the horizontal listview , i tried to warp horizontal listview and sizedbox for the arrow in Raw Widget but the arrow is always shown i wanna show when get the end of the list like this
Row(
children: [
const SizedBox(
width: 100,
height: 375,
child: Icon(
Icons.swipe_left_alt_rounded,
color: Colors.black,
size: 24,
)),
SizedBox(
height: 375,
width: SizeConfig.screenWidth * 0.8,
child: ListView.builder(
reverse: true,
scrollDirection: Axis.horizontal,
You can use itemBuilder to build items based on your need.
class AF extends StatelessWidget {
const AF({super.key});
#override
Widget build(BuildContext context) {
const itemLength = 4;
return Scaffold(
body: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: itemLength,
itemBuilder: (context, index) {
if (index == itemLength - 1) { // here will be the logic
return Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(Icons.arrow_back),
itemBuilder(index),
],
);
}
return itemBuilder(index);
},
),
);
}
Widget itemBuilder(int index) =>
Container(width: 200, child: Text("ItemNumber $index"));
}
Try use ListView swap outside Arrow Icon and ListView.builder:
This is demo code:
class TestScreen extends StatelessWidget {
const TestScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SizedBox(
height: 350,
child: ListView(
reverse: true,
scrollDirection: Axis.horizontal,
children: [
ListView.builder(
shrinkWrap: true,
reverse: true,
scrollDirection: Axis.horizontal,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return Container(
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(border: Border.all(width: 2)),
child: Padding(
padding: const EdgeInsets.all(30),
child: Center(
child: Text(
index.toString(),
),
),
),
);
},
itemCount: 10,
),
const SizedBox(
width: 100,
child: Icon(
Icons.swipe_left_alt_rounded,
color: Colors.black,
size: 24,
)),
],
),
),
);
}
}
I am an iOS developer, So I have idea how TabBarController works in iOS. Now I am working on Flutter (First APP).
I have an App which uses CupertinoApp-CupertinoTabScaffold-CupertinoTabBar to persist BottomNavigationBar in every nested screens.
My App's hierarchy
- CupertinoTabScaffold
-- CupertinoTabBar
--- Home
---- CupertinoPageScaffold (HomePage)
----- CupertinoPageScaffold (DetailPage pushed from home)
--- OtherTabs
To Push from HomePage to DetailPage, used below code:
Navigator.push(
context,
Platform.isIOS
? CupertinoPageRoute(
builder: (context) => DetailPage(),
)
: MaterialPageRoute(
builder: (context) => DetailPage(),
));
Now on detail screen I need Column for some view and GridView.
So when GridView have more items, it gives error:
A RenderFlex overflowed by 56 pixels on the bottom.
Which is space of TabBar.
So how to manage such type of pages in Flutter, having TabBar and scrollable Widgets in nested screens?
I have followed this link.
DetailPage Code:
class DetailPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
heroTag: 'detail 1',
backgroundColor: Colors.white,
transitionBetweenRoutes: false,
middle: Text('Tab 1 detail',),
),
child: Container(
child: Column(
children: <Widget>[
SizedBox(
height: 100.0,
child: Center(
child: Text('Some Menus'),
),
),
Container(
child: GridView.builder(
itemCount: 30,
scrollDirection: Axis.vertical,
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCountAndFixedHeight(
crossAxisCount: 2,
crossAxisSpacing: 4,
mainAxisSpacing: 4,
height: 160.0
),
itemBuilder: (context, index) {
return Container(
child: Padding(
padding: EdgeInsets.all(6.0),
child: Container(
decoration: BoxDecoration(
color: Color(0xFF3C9CD9),
borderRadius: BorderRadius.all(Radius.circular(30.0)),
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black54,
blurRadius: 2.0,
offset: Offset(4, 3))
]),
child: Padding(
padding: EdgeInsets.all(30.0),
child: Center(
child: Text('$index'),
),
)),
),
);
}
),
)
],
),
),
);
}
}
Output:
wrap the Grid with with Expanded widget
class DetailPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
heroTag: 'detail 1',
backgroundColor: Colors.white,
transitionBetweenRoutes: false,
middle: Text('Tab 1 detail',),
),
child: Container(
child: Column(
children: <Widget>[
SizedBox(
height: 100.0,
child: Center(
child: Text('Some Menus'),
),
),
Expanded(
child: Container(
child: GridView.builder(
itemCount: 30,
scrollDirection: Axis.vertical,
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCountAndFixedHeight(
crossAxisCount: 2,
crossAxisSpacing: 4,
mainAxisSpacing: 4,
height: 160.0
),
itemBuilder: (context, index) {
return Container(
child: Padding(
padding: EdgeInsets.all(6.0),
child: Container(
decoration: BoxDecoration(
color: Color(0xFF3C9CD9),
borderRadius: BorderRadius.all(Radius.circular(30.0)),
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black54,
blurRadius: 2.0,
offset: Offset(4, 3))
]),
child: Padding(
padding: EdgeInsets.all(30.0),
child: Center(
child: Text('$index'),
),
)),
),
);
}
),
),
)
],
),
),
);
}
}
My UI use case is similar to an Instagram user profile.
I have multiple widget on top and an infinite ListView.builder bellow with item.
I would like to scroll everything like within a ScrollView but the scrollview can not contain an infinite list.
How can I handle this situation in Flutter ?
Using CustomScrollView is the Solution
Here i have done Basic Implementation for you :
class MainBody extends StatefulWidget {
MainBody({Key key}) : super(key: key);
#override
_MainBodyState createState() => _MainBodyState();
}
class _MainBodyState extends State<MainBody> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: CustomScrollView(
slivers: <Widget>[
SliverToBoxAdapter(
child: Container(
padding:
const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Container(
height: 100,
width: 100,
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.green),
child: Center(child: Text("ProfileImage")),
),
flex: 1,
),
Expanded(flex: 2, child: Text("Profile Statistics"))
],
),
Text("Bio"),
Text("Some Buttons"),
Text("Story Highlights"),
])),
),
SliverToBoxAdapter(
child: Container(
height: 150,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 10,
itemBuilder: (context, index) {
return Container(
margin: const EdgeInsets.all(10),
height: 100,
width: 100,
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.red),
child: Center(child: Text((index + 1).toString())),
);
})),
),
SliverAppBar(
centerTitle: false,
pinned: true,
flexibleSpace: DefaultTabController(
initialIndex: 0,
length: 2,
child: TabBar(tabs: [
Center(child: Text("Icon1")),
Center(child: Text("Icon2")),
]),
),
),
SliverPadding(
padding: const EdgeInsets.all(8),
sliver: SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => Container(
height: 30,
child: Center(child: Text("Hey" + index.toString()))),
childCount: 20)),
)
],
),
);
}
}
Futher Enhancements can be done
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(
// ...
)
]
)
I have design like above, In that design I implement to app. I have Stack Widget inside container then inside Stack widget i have ListviewBuilder with Scroll direction Horizontal.
But the problem is, I cant scroll ListViewBuilder Horizontal inside Stack widget.
How can i fixed this ?
My Trial Fail
Source Code
class HomeScreen extends StatelessWidget {
static const routeName = "/home-screen";
#override
Widget build(BuildContext context) {
final mqHeight = MediaQuery.of(context).size.height;
final mqWidth = MediaQuery.of(context).size.width;
return SafeArea(
child: Scaffold(
appBar: AppBar(
elevation: 0,
title: Text('Good Morning'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.settings),
onPressed: () => "",
)
],
),
body: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
color: Colors.blue,
height: mqHeight / 3,
child: Stack(
overflow: Overflow.visible,
children: <Widget>[
Container(
color: Colors.red,
),
Positioned(
top: mqHeight / 4.5,
child: SizedBox(
height: 100,
child: ListView.builder(
physics: ClampingScrollPhysics(),
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
return Container(
width: 100,
child: Card(
elevation: 10,
child: Icon(Icons.card_giftcard)),
);
},
),
),
)
],
),
),
Container(
child: Text(
'data data data data data data data data data ',
style: Theme.of(context).textTheme.display4,
),
)
],
)),
),
);
}
}
You can copy paste run full code below
From https://github.com/flutter/flutter/issues/36584#issuecomment-554950474
Add top, right, bottom attribute
code snippet
Positioned(
top: mqHeight / 4.5,
left:0.0,
right:0.0,
bottom:0.0,
child: SizedBox(
height: 100,
child: ListView.builder(
working demo
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
static const routeName = "/home-screen";
#override
Widget build(BuildContext context) {
final mqHeight = MediaQuery.of(context).size.height;
final mqWidth = MediaQuery.of(context).size.width;
return SafeArea(
child: Scaffold(
appBar: AppBar(
elevation: 0,
title: Text('Good Morning'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.settings),
onPressed: () => "",
)
],
),
body: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
color: Colors.blue,
height: mqHeight / 3,
child: Stack(
overflow: Overflow.visible,
children: <Widget>[
Container(
color: Colors.red,
),
Positioned(
top: mqHeight / 4.5,
left:0.0,
right:0.0,
bottom:0.0,
child: SizedBox(
height: 100,
child: ListView.builder(
physics: ClampingScrollPhysics(),
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
return Container(
width: 100,
child: Card(
elevation: 10,
child: Icon(Icons.card_giftcard)),
);
},
),
),
)
],
),
),
Container(
child: Text(
'data data data data data data data data data ',
style: Theme.of(context).textTheme.display4,
),
)
],
)),
),
);
}
}
I have already fixed as below:
Positioned(
top: mqHeight / 4.5,
left: 0, /// <-- fixed here
right: 0, /// <-- fixed here
child: SizedBox(
height: 100,
child: ListView.builder(
physics: ClampingScrollPhysics(),
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
return Container(
width: 100,
child: Card(
elevation: 10,
child: Icon(Icons.card_giftcard)),
);
},
),
),
)```