I want the SingleChildScrollView to stay fixed - flutter

I used SingleChildScrollView in the table I created friends. I want SingleChildScrollView to stay on the screen all the time, how can I do this (i.e. I don't want it to be shown only when I come with the mouse)
my code
enter link description here
I want the scrollbar to stay fixed

wrap your List with ScrollBar.
set isAlwaysShown = true
Scrollbar(
isAlwaysShown: true,
child: GridView.builder(
itemCount: 10,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (BuildContext context, int index) {
return Center(
child: Text('item $index'),
);
},
),
);

Related

Flutter GridView off screen widgets destroyed on scroll

I have a screen with a GridView widget containing custom Cards with images and texts. When the app initially launches it loads all the cards and their images, however, they get destroyed when scrolled off the screen. Is there a way that I can stop flutter from destroying the off-screen widgets?
Expanded(
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 1.5,
),
itemCount: categories.length,
itemBuilder: (context, index) => CategoryCard(
category: categories[index],
),
),
),
Give flex or shrinkWrap: true, or use both
Expanded(
flex: 3, <--
child: GridView.builder(
shrinkWrap: true, <--
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 1.5,
),
itemCount: categories.length,
itemBuilder: (context, index) => CategoryCard(
category: categories[index],
),
),
),
Figured it out! GridView, ListView, etc., have addAutomaticKeepAlives and cacheExtent properties. By default addAutomaticKeepAlives: true doesn't destroy off-screen widgets, and providing the cacheExtent: DOUBLE VALUE describes how many pixels the cache area extends before the leading edge and after the trailing edge of the viewport.

When adding ListView builder , the entire screen is goes blank

when I try to add a list view builder, my entire screen goes black
here is the list view builder code
ListView.builder(
shrinkWrap = true,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
final data = courseCardList[index];
return Row(
children: [
CourseList(
color: data.color,
icon: data.icon,
caption: data.caption,
head: data.head,
timePeriod: data.timePeriod,
rating: data.rating,
),
],
);
},
),
when I build the UI, that shows a blank screen, what mistake am I making here?
Horizontal Listview.builder needs a fixed height. Horizontal list item shouldn't have a endless height. so solution came to my mind just wrap Listview.builder with a conatiner and set height of that container like below.
The Flutter framework can only know the height of a widget once it's been built.
If you're building ListView children dynamically, it can't calculate the required height of the ListView until all it's children have been built, which might never happen (infinite ListView).
You can either give the ListView a fixed height and build its children dynamically or have the ListView's height depend on it's children.
Container(
height: 200,
child: ListView.builder(
shrinkWrap = true,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
final data = courseCardList[index];
return Row(
children: [
CourseList(
color: data.color,
icon: data.icon,
caption: data.caption,
head: data.head,
timePeriod: data.timePeriod,
rating: data.rating,
),
],
);
},
),
);
Under ListView Widget
use shrinkWrap: true
add itemCount, itemCount: courseCardList.length
If it still doesn't solve the issue,
Remove the Row() widget as I can see you are only returning a single widget under it, so directly return that widget CourseList()
The code should look something like this.
ListView.builder(
shrinkWrap : true,
itemCount: courseCardList.length,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
final data = courseCardList[index];
return CourseList(
color: data.color,
icon: data.icon,
caption: data.caption,
head: data.head,
timePeriod: data.timePeriod,
rating: data.rating,
);
},
),
I think you forgot the itemCount
Expanded(
child:ListView.builder(
shrinkWrap = true,
itemCount = 5,// add this line or put courseCardList.length
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
final data = courseCardList[index];
return Row(
children: [
CourseList(
color: data.color,
icon: data.icon,
caption: data.caption,
head: data.head,
timePeriod: data.timePeriod,
rating: data.rating,
),
],
);
},
),
),
Refer ListView and Long List
provide itemCount to your ListviewBuilder and also wrap it with Expanded or some fixed size widget like container like:
Expanded(
child: ListView.builder(
itemCount: your counts(int)
.....
.....
)
)

Flutter Listview builder show data in two rows depending upon `index` is odd or event

I am fairly new in Flutter, I am fetching data from api and displaying it in a listview. I have following demo code.
/*Other codes*/
return ListView.builder(
//Other Codes
physics: const AlwaysScrollableScrollPhysics(),
itemCount: item.length,
padding: new EdgeInsets.only(top: 5.0),
itemBuilder: (context, index) {
});
My requirement is to show data in Two Rows, such that if the item in index is even show it in first row and if its odd, show it in another row? More like in the Image below.
Update: There could be many items and can be scrolled horizontally to reveal more items.
Can we achieve this without manipulating the data received from API? From API the data comes in date-wise sorted in descending order.
Thanks
GridView.builder is probably what you are looking for.
Just give it scrollDirection: Axis.horizontal to make it horizontal.
Then give it gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2) to make sure you have only 2 rows.
Then use SizedBox to restrict the height of the GridView to 90 + 90.
Finally, use the childAspectRatio property of the SliverGridDelegateWithFixedCrossAxisCount to specify that you want your aspect ratio to be 90 / 256.
Color randomColor() => Color.fromARGB(255, Random().nextInt(255), Random().nextInt(100), Random().nextInt(200));
class MyApp extends StatelessWidget {
List<String> array = ["0", "1", "2", "3"];
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Example')),
body: SizedBox(
height: 90 + 90,
child: GridView.builder(
itemCount: 4,
scrollDirection: Axis.horizontal,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
childAspectRatio: 90 / 256,
crossAxisCount: 2,
),
itemBuilder: (context, index) {
return Container(
color: randomColor(), child: Text(array[index])
);
}
),
),
),
);
}
}

Flutter: unexpected space at the top of ListView

I have the following source code:
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
controller: scrollController,
slivers: <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(context, cardIndex) {
return Container(
color: Colors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Main Course',
style: kRestaurantMenuTypeStyle,
),
ListView.builder(
itemCount: menuCards[cardIndex].menuItems.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
itemBuilder: (context, itemIndex) {
return RestaurantMenuItem(
menuItem: menuCards[cardIndex].menuItems[itemIndex],
);
},
),
],
),
);
},
childCount: menuCards.length,
),
),
],
),
);
}
Unfortunately, the ListView.builder() creates this extra space on top automatically. This is shown in the image below. That is the big white space between the 'Main Course' and 'Pancit Malabon' texts.
I don't understand why ListView does that. How do I remove the space?
To avoid this behaviour of listview, override padding property with a zero [padding]
return ListView.builder(
padding: EdgeInsets.zero,
itemCount: data.items.length,
itemBuilder: (context, index) {}
);
Looking at your screenshot, the ListView scrolls close to the top of the screen and by default, ListView adds a padding to avoid obstructing the system UI. So a zero padding would remove the extra space.
By default, ListView will automatically pad the list's scrollable
extremities to avoid partial obstructions indicated by MediaQuery's
padding. To avoid this behavior, override with a zero padding
property.
Source : ListView
I solved the issue by adding a padding to my list view like so:
ListView.builder(
padding: EdgeInsets.only(top: 0.0),
...
),
I don't understand why the solution works. If someone can explain the bug, I can accept theirs as the correct answer.
You can wrap your listview with MediaQuery.removePadding
MediaQuery.removePadding(
context: context,
removeTop: true,
child: ListView(...),
)

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