How to add other components additional to gridview on same page in flutter - flutter

...
if (snapshot.data == null) {
return Container(
child: Center(
child: Text("Loading..."),
));
} else {
return GridView.builder(
itemCount: snapshot.data.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3),
itemBuilder: (context, index) => Card(
child: GridTile(
child: Center(
child: Text(snapshot.data[index].service_type),
),
)));
}
...
When this code is executed, the result is as follows,
In this, I need to add an image component on top of the grids. Please help me on achieving that. The below image is the expected result design.

Using shrinkWrap on big lists is a bad practice, you should wrap your GridView/ ListView with expanded when you want something above or below it, also don't nest scroll views like that. You should use CustomScrollView or NestedScrollView instead. What they said in the docs.
Shrink wrapping the content of the scroll view is significantly more expensive than expanding to the maximum allowed size because the content can expand and contract during scrolling, which means the size of the scroll view needs to be recomputed whenever the scroll position changes.

Related

Flutter ListView entries cut off when scrolled down

A screen in my app displays a list of "listings" the user has made. In the event there is not enough listings to fill the whole screen, and the user scrolls down, the listing they are scrolling will get cut off instead of being scrolled down.
example before scrolling
example after scrolling
As the user scrolls the list entry downwards I would like it not to disappear. I've tried wrapping the listview.builder in containers / sized boxes to define their size, although this behavior persists. I thought I could also put in some blank entries into the list that wouldn't respond to user clicks but that seems like an inefficient solution. Here is my code:
return Scaffold(
key: listing_home_scaffold_key,
resizeToAvoidBottomInset: false,
backgroundColor: BODY_BACKGROUND_COLOR,
appBar: returnAppBarForHomePages(context, "Listings", widget.local_user, updateUserState,
widget.local_user.usingDefaultImage, widget.local_user.getProfilePicURL, listing_home_scaffold_key),
drawer: settingsDrawer(widget.local_user),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
returnScrollableListView()
]),
);
Widget returnScrollableListView() {
return RefreshIndicator(
child: ListView.builder(
physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
itemCount: user_listings.length,
shrinkWrap: true,
padding: const EdgeInsets.only(top: 0),
itemBuilder: (context, index) {
return UserListing(listing: user_listings[index]);
}),
onRefresh: () async {
var cancel_loading_indicator = showLoadingIndicatorAllowClick();
await reQueryData();
cancel_loading_indicator();
},
);
}
Edit: Having the refresh indicator be the direct parent to the listview caused this problem. Moving it up a level so it's instead the parent of the Column fixed this.
Having the refresh indicator be the direct parent to the listview caused this problem. Moving it up a level so it's instead the parent of the Column fixed this.

Is there any alternatives Transform widget to animate the scale of widget inside PageView.builder?

I am trying to build a design with the help of PageView.builder. I don't want to use a plugin, since this design is bit different and also I can't get more flexible if I want to try something new.
The design is pretty simple, I'm trying to build a bottomNav using PageView. The design looks like Carousel for me, hence decided to go with PageView, correct me if I am wrong. It is not only sliding widget. If I press any visible CircleAvatar, it will be come to the middle (active we can say)
As of now, I achieved this
Here you can see the gap difference due to Transform. It is occupying space. I tried with AnimatedSize widget but not able to mimic this design.
Code as far I have
PageView.builder(
controller: pageController,
scrollDirection: Axis.horizontal,
itemCount: pages.length,
onPageChanged: (index) => setState(() {}),
scrollBehavior: NoScrollGlowBehaviour(),
itemBuilder: (context, index) {
return GestureDetector(
onTap: () => gotoPage(index),
child: _buildBottomNavAnimated(index),
);
Widget _buildBottomNavAnimated(int index) {
Matrix4 matrix4 = Matrix4.identity();
//computing matrix based on diff currentPage values
return Transform(
transform: matrix4,
alignment: Alignment.center,
child: CircleAvatar(
backgroundColor: pages[index],
child: const FlutterLogo(
size: 20,
),
),
);
}
I just added minimal required code above. For full code dartpad . Incase needed Inspect image for help
I would also like, if it is possible to achieve this design apart from PageView and Transform too.

Wrap item different height in vertical PageView - Flutter

I have a vertical PageView with different item height :
But I would like to wrap each item according their height.
The final result I want here:
How can we do this ?
UPDATE 2022:
After some time, I returned to this problem and have now created a smart and slim pub.dev package with way more features, less buggy, and maintained code.
SnappyListView(
itemCount: Colors.accents.length,
itemBuilder: (context, index) {
return Container(
height: 100,
color: Colors.accents.elementAt(index),
child: Text("Index: $index"),
),
);
For those still interested in a non-packages solution (not recommended), make sure to check out the edit queue of this answer.
first of all, you should use SafeArea in order to prevent your widgets go through the notch. see [this][1].
Then you should use ListView instead of PageView because PageView creates pages with the same sizes. in ListView create an array of int that stores height of widget and use it to create widgets with different size.
List<int> heights = [100, 120, 10];// and so on
\\then use it as follow:
ListView.builder(
itemCount: 6,
itemBuilder: (context, i){
return Container(
height:heights[i],
width: 200, // or any value you want
padding: const EdgeInsets.all(8.0),
alignment: Alignment.center,
child: YourWidget);
},
),
[1]: https://stackoverflow.com/questions/49227667/using-safearea-in-flutter#:~:text=SafeArea%20is%20basically%20a%20glorified,%22creative%22%20features%20by%20manufactures.

How to dynamically increase the height of a list and scroll after reaching a max height?

Hi i'm trying to create a list view to which i dynamically add items in the app. I want the height of the list to grow till it reaches a defined max height, and then show a scrollbar when it overflows.
_buildPage() {
return Container(
width: widget.width,
constraints: BoxConstraints(
maxHeight: widget.maxHeight,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_buildTitle(),
_buildAddBump(),
ListView.builder(
itemCount: _items.length,
itemBuilder: (context, index) => _buildItem(_items[index]),
),
],
),
);
}
This is of course not working since a ListView needs a pre-defined height. But wrapping the ListView in an Expanded will take all the remaining height and the ListView will be at maxHeight even when the items in it don't need the height.
I've tried putting the items in a SingleChildScrollView with a Column as a child, but that doesn't seem to do anything. The widget just overflows when i add more items than the height can hold. Is there a way to give a max height constraint to a list and tell it to take the height of its contents till it reaches the max height?
UPDATE:
I tried to add shrinkWrap: true to the ListView, but it's still not working. The page renders without errors and the ListView height increases as items are added, but when the height goes beyond maxHeight, it just overflows instead of adding a scroll.
Seems like I found the solution and it's quite easy. Wrap your ListView inside Flexible and set shrinkWrap to true:
...
Flexible(
child: ListView.builder(
itemCount: _items.length,
itemBuilder: (context, index) => _buildItem(_items[index]),
shrinkWrap: true,
)
),
...
If it's not the solution, let me know what is wrong in comments.

Refresh indicator doesn't work when list doesn't fill the whole page

I have a page the has a list with refresh indicator. When I have many elements in the list (filling the whole view and more, i.e. I can scroll), the refresh indicator works.
However, when I have only one or two elements in the list (nothing to scroll), then the refresh indicator doesn't work. Is this the expected behaviour? Is there a way to get the indicator to work also for short lists?
I tried wrapping the list view (child of refresh indicator) with a scroll bar but the problem still persists.
Future<void> _onRefresh() async {
_getPeople();
}
#override
Widget build(BuildContext context) {
super.build(context);
return new Container(
child: _items.length == 0
? Center(child: CircularProgressIndicator())
: new RefreshIndicator(
onRefresh: _onRefresh,
child: Scrollbar(
child: new ListView.builder(
controller: controller,
itemBuilder: (context, index) {
return PeopleCard(
People: _items[index],
source: 2,
);
},
itemCount: _items.length,
),
)),
);
}
If the length of the items list is 1 or 2 or any amount that doesn't need scrolling, refresh indicator should also work.
Set the physics to AlwaysScrollableScrollPhysics just like the below code.
new RefreshIndicator(
key: _refreshIndicatorKey,
color: Colors.blue,
onRefresh: (){
setState(() {
_future = fetchPosts(http.Client());
_getAvalailableSlots();
});
},
child: ListView.builder(
physics: AlwaysScrollableScrollPhysics(),
itemCount: data.length,
itemBuilder: (context, i) {
//do something
}
)
)
Case 1:
Use AlwaysScrollableScrollPhysics() in your Listview or SingleChildScrollView.
physics: const AlwaysScrollableScrollPhysics(),
Case 2:
If you want to use other scroll physics, use this way...
physics: BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics(),
),
Case 3:
Make sure you didn't make shrinkWrap, true. ShrinkWrap has to be false like default.
shrinkWrap: true. ❌
shrinkWrap: false. ✅
shrinkWrap: false,
Case 4:
If you have any custom widgets other than a listview, use stack and listview this way...
RefreshIndicator(
onRefresh: () async {
print('refreshing');
},
Stack(
children: [
YourWidget(),
ListView(
physics: const AlwaysScrollableScrollPhysics(),
),
],
),
),
To use with BouncingScrollPhysics:
RefreshIndicator(
onRefresh: () async {
},
child: ListView.builder(
physics: BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics()),
itemBuilder: (context, index) {
return Text("${index}");
}),
To make RefreshIndicator always appear, set physics: const AlwaysScrollableScrollPhysics() for the scrollable child like below.
ListView(
physics: const AlwaysScrollableScrollPhysics(),
children: <Widget>[widget.bodyWidget]
)
If you still have some errors, the below might help.
ListView widget needs to have height value to be "always" scrollable vertically. So wrap it with SizedBox or some other proper widget and set the height.
How to fix the height? Get the height of viewport using MediaQuery.of(context).size.height and, if needed, subtract the value of non-scrollable part.
If you use SingleChildScrollView and it's not working with AlwaysScrollableScrollPhysics(), it is because the child doesn't have height. fix the child's height or just use ListView.
To sum up, the following worked for me.
sizes.bottomNavigationBar and sizes.appBar are the constant variables I made to customize the appbar and navbar.
RefreshIndicator(
onRefresh: widget.onRefresh,
child: SizedBox(
height: MediaQuery.of(context).size.height -
sizes.bottomNavigationBar -
sizes.appBar,
child: ListView(
physics: const AlwaysScrollableScrollPhysics(),
children: <Widget>[widget.bodyWidget]
)),
)
If you're finding any reliability, Refresh indicator does not show up part of the official doc would help.
If you're using ListView inside of Column with Expanded.
Try Removing
shrinkWrap:true