How to prevent gridview from shrinking in flutter? - flutter

I'm making an application in flutter.
And i wanna show some list of items using GridView, showing 3 items in a row. And make their size flexible depend on the devices.
But Actually what i coded doesn't work properly.
When device screen is somewhat narrow, they shrink and messed up like this.
But when the device screen become wider, the size of image doesn't expand but only the spaces between the items expanded like below.
I wanna make the pictures fill the screen. How can i make it?
Thank you for concerning my question, and i'm sorry about the foreign languages in the picture.
return Scaffold(
appBar: AppBar(
title: Text("${getUnitBookClassTitlebyTag(tag!)} 목록"),
backgroundColor: Color(COLOR_PRIMARY),
centerTitle: true,
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: CustomScrollView(
primary: false,
slivers: <Widget>[
SliverPadding(
padding: const EdgeInsets.all(20),
sliver: SliverGrid.count(
crossAxisSpacing: 10,
mainAxisSpacing: 10,
crossAxisCount: 3,
children: <Widget>[
for (UnitBook _curUnitBook in unitBookList!)
UnitBookDisplay(
bookData: _curUnitBook,
imageHeight: null,
imageWidth: null),
],
),
),
],
)),
);
/***
Widget build(BuildContext context) {
//bookDataReplace();
//debugPrint('cover : ${bookData!.coverUrl!}');
//debugPrint('cover : ${bookData!.coverUrl!.replaceAll('\\/', '/')}' );
if (bookData == null) debugPrint('bookData is null!!');
return Column(
children: [
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) =>
DetailScreen(book: convertUnitBooktoBook(bookData!)),
),
);
},
child: Expanded(
child: Container(
margin: EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 10.0),
height: imageHeight,
width: imageWidth,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
boxShadow: [
BoxShadow(
color: Colors.black54,
offset: Offset(0.0, 4.0),
blurRadius: 6.0,
),
],
),
child: ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: (bookData!.coverUrl == null)
? (Image(
image: AssetImage('images/default_book_cover_image.png'),
fit: BoxFit.cover,
))
: (Image.network(
'${bookData!.coverUrl!.replaceAll('\\/', '/')}',
fit: BoxFit.cover,
)),
),
),
),
),
SizedBox(
child: Text((bookData!.title == null) ? 'unNamed' : bookData!.title!,
overflow: TextOverflow.ellipsis),
width: imageWidth,
),
],
);
}

While using SliverGrid or GirdView, childAspectRatio decide its children size. While children having fixed height on
child: Expanded(
child: Container(
margin: EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 10.0),
height: imageHeight, //<- here
Bottom RenderFlex overflowed occurs only when SliverGrid failed to provide enough height for the children.
You can try removing fixed height from here only UI don't face any issue, but for better design purpose use childAspectRatio on SliverGrid.count, something like
SliverGrid.count(
crossAxisCount: 3,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
childAspectRatio: 3 / 4,// width/height : check and change the way you want.
children: ....
Also, you can try Wrap.

Related

Flutter scroll only on some widgets

I am making an application where you can edit the profile picture and I want to scroll only when I click on a piece of the screen.
The screen as you see in the picture is divided 50 - 50, the top part is the profile picture, and inside it you can move to select the part that is inside the circle (you can also zoom).
The lower part is the gallery with the latest photos.
Example
What I want to do, is that if I click on the upper part, it does not scroll, it simply works with the zoom that already has that widget. And if I click in the inferior part, I want that a complete zoom is done, that is to say that it raises the whole screen, including the profile photo.
My code is the following:
CustomScrollView(
slivers: [
SliverToBoxAdapter(child: SizedBox(
height: maxHeight,
child: Stack(
children: [
Positioned(
top: 0.1,
child: SizedBox(
height: maxHeight,
width: Sizes.width,
child: Stack(children: [
Positioned.fill(
child: PhotoView(
backgroundDecoration: BoxDecoration(color: Colors.transparent),
minScale: PhotoViewComputedScale.covered,
onScaleEnd: (c, details, controllerValue) {
},
enableRotation: false,
imageProvider: NetworkImage(
'https://i.stack.imgur.com/lkd0a.png',
),
),
),
]),
),
),
IgnorePointer(
child: ClipPath(
clipper: InvertedCircleClipper(),
child: Container(
color: Colors.black.withOpacity(0.3),
)),
),
],
)))),
SliverPadding(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
sliver: SliverToBoxAdapter(
child: Row(children: [
Text(
'gallery'.tr,
),
Icon(Icons.keyboard_arrow_down_rounded)
]),
)),
SliverPadding(
padding: edgeInsets,
sliver: SliverGrid(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 4,
mainAxisSpacing: 4,
),
delegate: SliverChildBuilderDelegate((context, index) {
final image = localImages[index];
return ClipRRect(
borderRadius: BorderRadius.circular(10),
child: FadeInImage(
width: 400,
height: 400,
placeholder: MemoryImage(kTransparentImage),
image: DeviceImage(image, size: const Size(400, 400), quality: 90),
fit: BoxFit.cover,
),
);
},
childCount: localImages.length),
)
],
),
How can I do it? Thank you.

I tried to wrap column with Singlechildscrollview Flutter but screen goes blank

[enter image description here][1]
Inside My column, there is a stack, a carousel slider,a gridview builder. I want to scroll all of them together. I tried to use singlechildscrollview as you can see in the code below. Please Someone help me how can I scroll those things together.
[1]: https://i.stack.imgur.com/FYexC.png` enter code here`
Scaffold(
backgroundColor: Colors.orange,
// Color(0xFFFFF176),
body: SingleChildScrollView(
child: Column(
children: [
Expanded(
child: Stack(
alignment: Alignment.bottomCenter,
children: [
CarouselSlider(
items: slideImage
.map((image) =>
Builder(builder: (BuildContext context) {
return Container(
height: 200,
width: 500,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(40),
image: DecorationImage(
image: AssetImage(image),
fit: BoxFit.fill),
),
);
}))
.toList(),
options: CarouselOptions(
onPageChanged: (index, reason) {
setState(() {
activeIndex = index;
});
},
height: 300,
viewportFraction: 1,
autoPlay: true,
),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: AnimatedSmoothIndicator(
activeIndex: activeIndex, count: slideImage.length),
),
],
),
),
SizedBox(
height: 10,
),
Expanded(
child: GridView.builder(
shrinkWrap: true,
// physics: NeverScrollableScrollPhysics(),
itemCount: menuImage.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.8,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
),
itemBuilder: (context, index) => Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
color: Color(0xFFFFFDE7),
elevation: 10,
child: GridTile(
child: Column(
children: [
Image.asset(
menuImage[index],
fit: BoxFit.fill,
),
Text(
title[index],
style: TextStyle(fontSize: 18),
),
],
),
),
),
),
),
],
),
),
);
}
}
It would be best if you gave height to the column you are using singlechildeScrollview.
Wrap column widget in container or sizedbox widget and give it height.
column widget has children widget GridView.builder that is wrapped in expanded so gridview.builder will try to take all available height in the column which will be infinite because it's not defined and you will get column covering screen taking infinite screen height in short blank screen.
In flutter, Column will take height as much as it can, SingleChildScrollView child dont have height (infinite). Combine together, Flutter don't know how to render them correctly and causing error.
To solve it, try to determine the height of Column by widgget like SizedBox or determine the mainSize.min.
Another way to solve it is wrap Column by IntrinsicHeight but not recommend cause it heavy.
If it takes too much height. so give height to the column.
like this..
SingleChildScrollView(
child: SizedBox(
height: 500,
child: Column(
children: const [...],
),
),
)
your expanded widget is taking whole space of column try removing it or replacing it with Sizedbox.

how to Make whole page scrollable instead to GridView Builder in flutter?

I am new to flutter and creating a screen with following code:-
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:wallpaper/ui/widgets/card_wallpaper.dart';
import '../../providers/anime_provider.dart';
import '../../models/wallpaper.dart';
import '../../providers/wallpaper_provider.dart';
class AnimeDetail extends StatelessWidget {
#override
Widget build(BuildContext context) {
final String id = ModalRoute.of(context).settings.arguments;
final selectedAnime = Provider.of<AnimeProvider>(context).findById(id);
final selectedWallPaper =Provider.of<WallpaperProvider>(context).getByAnime(id);
final appBar = AppBar(
leading: BackButton(
color: Theme.of(context).primaryColor,
),
elevation: 0,
backgroundColor: Colors.transparent,
title: Text(
selectedAnime.title,
style: TextStyle(
color: Theme.of(context).primaryColor,
fontFamily: 'Righteous',
),
),
);
final mediaQuery = MediaQuery.of(context);
final double totalHeight = mediaQuery.size.height -appBar.preferredSize.height -mediaQuery.padding.top -335;
return Scaffold(
appBar: appBar,
body: SingleChildScrollView(
child: Column(
children: [
Container(
width: double.infinity,
height: 300,
child: Card(
elevation: 3.1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: Stack(
children: [
Container(
height: 300,
width: double.infinity,
child: ClipRRect(
child: Image.asset(
selectedAnime.imageUrl,
fit: BoxFit.cover,
),
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20),
),
),
),
],
),
),
),
SizedBox(height: 10),
Row(
children: [
Container(
height: 25,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 15, vertical: 0),
child: Text(
'WallPapers from ${selectedAnime.title}',
style: TextStyle(
fontFamily: 'Righteous',
fontSize: 16,
color: Theme.of(context).primaryColor,
),
),
),
),
],
),
Container(
width: double.infinity,
height: totalHeight,
child: GridView.builder(
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.5,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
itemBuilder: (ctx, i) => ChangeNotifierProvider.value(
value: selectedWallPaper[i],
child: CardWallpaper(),
),
padding: const EdgeInsets.all(8.0),
itemCount: selectedWallPaper.length,
),
),
],
),
));
}
}
When I run this app, the gridview is scrollable but the image at the top of it does not scroll,but, I want to scroll whole page but only the grid scrolls even though I am using singlechildscrollview. I tried using expanded on gridview builder but it produces error.How can I make whole page scroll instead of just gridview.builder.
![See the screen here]:https://i.stack.imgur.com/ClDZy.jpg
As you can see when you scroll the page only gridview gets scrolled while top image remains there. I want to scroll the page as whole. Is there any way to determine the height of gridtile?
In your gridview, set the parameter scrollable: NeverScrollablePhysics().

Flutter "NoSuchMethodError: The getter 'position' was called on null" when sticky header is used to wrap around GirdView.builder widget

Trying to use sticky header to wrap around a GridView.builder widget, because I want to have a header follow when the user scrolls down enough the screen, but getting "NoSuchMethodError: The getter 'position' was called on null. Receiver: null Tried calling: position See also: https://flutter.dev/docs/testing/errors". I use this same widget to wrap around a Column widget. I tried wrapping the GridView with Container, Column and other widgets. I would just get other errors. What does this error mean?
return _stickyHeader.render(
headerChild: Text(''),
content: GridView.builder(
shrinkWrap: true,
physics: ScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 5.0,
mainAxisSpacing: 5.0,
),
itemCount: state.avatarUrlList.length,
itemBuilder: (BuildContext context, int index) {
if (index == state.currentSelectedAvatarIndex) {
return Center(
child: InkWell(
onTap: () => _onAvatarImageClicked(
state.avatarUrlList[index], index),
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Colors.red,
width: 4.0,
),
),
child: CircleAvatar(
radius: 60,
backgroundColor: Colors.transparent,
backgroundImage:
NetworkImage(state.avatarUrlList[index]),
),
),
),
);
} else {
return Center(
child: InkWell(
onTap: () => _onAvatarImageClicked(
state.avatarUrlList[index], index),
child: CircleAvatar(
radius: 60,
backgroundColor: Colors.transparent,
backgroundImage:
NetworkImage(state.avatarUrlList[index]),
),
),
);
}
},
),
);
}
Widget render({Widget headerChild, Widget content}) {
return StickyHeader(
header: Container(
decoration: BoxDecoration(
color: ThemeConstants.ceruleanCrayola,
borderRadius: BorderRadius.circular(15),
),
height: 50.0,
padding: EdgeInsets.symmetric(horizontal: 16.0),
margin: EdgeInsets.symmetric(horizontal: 20.0),
alignment: Alignment.centerLeft,
child: headerChild,
),
content: content,
);
}
Based on https://pub.dev/packages/sticky_headers
You can place a StickyHeader or StickyHeaderBuilder inside any scrollable content, such as: ListView, GridView, CustomScrollView, SingleChildScrollView or similar.
You may need to try put your StickyHeader to SingleChildScrollView for basic.

Why is Gridview.count not filling out the space with my dynamic content

I am trying to create a gridview starting from the second column. The first card is just a static card with a button in it. So the second card starting should be dynamic.
All the cards have the same width and height. So basically they all should look like the first card (Add a new dog)
But it's not filling out the space as I expected it would.
Here is part of my code from the body section:
body: Stack(fit: StackFit.expand, children: [
//bg image
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(Images.bgYellow), fit: BoxFit.cover)),
),
//content
SafeArea(
bottom: false,
left: true,
right: true,
top: false,
child: Padding(
padding: EdgeInsets.all(3 * SizeConfig.safeBlockHorizontal),
child: GridView.count(
crossAxisCount: 2,
children: [
//add card
Container(
margin: EdgeInsets.symmetric(
vertical: 1 * SizeConfig.blockSizeVertical,
horizontal: 2 * SizeConfig.blockSizeHorizontal),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 2,
blurRadius: 8,
offset: Offset(
0, 2), // changes position of shadow
),
],
),
child: FlatButton(
onPressed: null,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
const IconData(0xe901,
fontFamily: 'icDog'),
color: muddyBrown,
size: 20 * SizeConfig.safeBlockHorizontal,
),
SizedBox(height: 5),
Text(
"ADD A NEW DOG",
style: TextStyle(
color: muddyBrown,
fontWeight: FontWeight.bold,
fontSize: 4 *
SizeConfig.safeBlockHorizontal),
)
],
)),
),
//dynamic content
StateBuilder<PetState>(
observe: () => _petStateRM,
builder: (context, model) {
return Column(
children: [
...model.state.pets.map((pet) =>
GestureDetector(
onTap: () {
Navigator.pushNamed(
context, petDetailRoute);
},
child: Container(
margin: EdgeInsets.symmetric(
vertical: 1 *
SizeConfig
.blockSizeVertical,
horizontal: 2 *
SizeConfig
.blockSizeHorizontal),
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(30),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey
.withOpacity(0.5),
spreadRadius: 2,
blurRadius: 8,
offset: Offset(0,
2), // changes position of shadow
),
],
),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
//dynamic data => Photo + Name
children: [
Container(
width: 100.0,
height: 100.0,
decoration: new BoxDecoration(
color:
const Color(0xff7c94b6),
image: new DecorationImage(
image: new NetworkImage(
"${pet.photo}"),
fit: BoxFit.cover,
),
borderRadius:
new BorderRadius.all(
new Radius.circular(
50.0)),
border: new Border.all(
color: muddyBrown,
width: 4.0,
),
),
),
SizedBox(height: 5),
Text(
"${pet.name}",
style: TextStyle(
fontSize: 4 *
SizeConfig
.safeBlockHorizontal,
color: muddyBrown,
fontWeight:
FontWeight.bold),
)
],
),
),
))
],
);
}),
],
)
)),
]));
What about simply adding the 'static' card to the 'dynamic' ones and then build one GridView with all of them together?
Widget newDogButton = Card(...);
//dynamic content
StateBuilder<PetState>(
observe: () => _petStateRM,
builder: (context, model) {
return Column(
children: [
newDogButton,
...model.state.pets.map((pet) => // ...
That should take care of most of your layout issues automatically.
Because StateBuilder return a widget. How about moving the Whole GridView inside it?
...
child: Padding(
padding: EdgeInsets.all(3 * SizeConfig.safeBlockHorizontal),
child: StateBuilder<PetState>(
observe: () => _petStateRM,
builder: (context, model) {
return GridView.count(
crossAxisCount: 2,
children: [
// The button "ADD A NEW DOG" here,
Container(...),
//dynamic content here
...model.state.pets.map((pet) =>
...
).toList(),
},
),
),
Every grid item in GridView will have same height and width, if you want different dynamic height or width for different items, use flutter_staggered_grid_view, in your case:
StaggeredGridView.countBuilder(
crossAxisCount: 2,
itemCount: 2,
itemBuilder: (BuildContext context, int index) => new Container(
color: Colors.green,
child: new Center(
child: new CircleAvatar(
backgroundColor: Colors.white,
child: new Text('$index'),
),
)),
staggeredTileBuilder: (int index) =>
new StaggeredTile.count(1, index.isEven ? 2 : 1),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
)
The situation:
To me, this problem is not coming from your Dynamic content but from the height allowed to it to display it's content. Inside the GridView.count constructor, the default childAspectRatio value is 1.0, meaning that the default max height of each child of the GridView is deviceWidth / crossAxisCount (2 in your case).
The problem:
In order for each child to display correctly, it's height must not exceed this ratio (causing your overflowed error).
My opinion:
To solve this problem, I will either replace the dynamic content StateBuilder<PetState> with a static Widget which height will not exceed the ratio OR wrap the dynamic content StateBuilder<PetState> in a SingleChildScrollView to ensure that the overflowed error will not happen and the wrapper can produce the scroll effect to see the entire dynamic content.