SingleChildScrollView with ListView in a showModalBottomSheet [duplicate] - flutter

This question already has answers here:
How to Move bottomsheet along with keyboard which has textfield(autofocused is true)?
(24 answers)
Closed 6 months ago.
I am using a SingleChildScrollView with a ListView in a showModalBottomSheet but the keyboard is hidding the field when the user is filling it.
showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
isDismissible: false,
builder: (context) {
return SafeArea(
child: Container(
decoration: ...
child:Column(
children:[
Text("...),
Expanded(
child: SingleChildScrollView(
child: ListView.separated(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: list.length,
itemBuilder: (BuildContext context, int index) {
return TextField(...)
]);
},
separatorBuilder: (BuildContext context, int index) => const Divider(),
),
),
),
Button(...),
]),
));
}

Wrap your modal builder with SingleChildScrollView and add padding to it like this:
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
full example:
showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
isDismissible: false,
builder: (context) {
return SingleChildScrollView(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: Container(
decoration: BoxDecoration(
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(8.0),
topRight: const Radius.circular(8.0)),
),
padding: EdgeInsets.only(left: 16, right: 16, bottom: 16),
child: Column(
children: [
ListView.separated(
// padding: EdgeInsets.zero,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: list.length,
itemBuilder: (BuildContext context, int index) {
return TextField(
decoration: InputDecoration(hintText: 'text'),
);
},
separatorBuilder: (BuildContext context, int index) =>
const Divider(),
),
ElevatedButton(
onPressed: () {
_showBottom(context);
},
child: Text('button')),
],
),
),
);
})
when keyboard is close:
when it is open:

You can add the SingleChildScrollView up right after the safearea widget.
Now, you will get an error because the children does not have a boundary height.
You can use the height of the screen to set the container height.
Then add padding to the SingleChildScrollView matching the keyboard height
Showing lines with significant changes below
showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
isDismissible: false,
builder: (context) {
return SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: Container(
height: MediaQuery.of(context).size.height,
child: Column(children: [
TextField(),
Expanded(
child: ListView.separated(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: 10,
itemBuilder: (BuildContext context, int index) {
return TextField();
},
separatorBuilder:
(BuildContext context, int index) =>
const Divider(),
),
),
TextField(),
]),
),
),
);
});

Related

ListView.builder() builds all items in an ExpansionTile

In a list of expansion tile widgets, I'm trying to build a list (200+ items) when any expansion tile is opened. When i open the expansion tile it builds all the 200 items at once, giving a jank. I'm using Listview.builder so I'm not expecting this behavior. Here's a code snippet.
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: 100,
itemBuilder: (context, i) {
final _expansionTileKey = GlobalKey();
return ExpansionTile(
initiallyExpanded: false,
textColor: Colors.black,
key: _expansionTileKey,
onExpansionChanged: (value) =>
widget.onExpansionChanged(_expansionTileKey),
trailing: Icon(
Icons.keyboard_arrow_down,
),
subtitle: Text(
"$i - $i",
),
title: Text(
'$i',
),
children: <Widget>[
StreamBuilder<List<T>>(
stream: _bloc.stream,
builder: (context, snapshot) {
return ListView.separated(
shrinkWrap: true,
itemCount: _bloc.length,
itemBuilder: (_, index) {
return Container(
color: Colors.white,
child: Text("$index"),
);
},
separatorBuilder: (_, i) => Padding(
padding: const EdgeInsets.only(left: 8, right: 8),
child: const Divider(
height: 1,
),
),
);
},
)
],
);
},
),

Flutter. How to open a specific picture from image grid?

I have an image grid "StaggeredImageGrid" and what I want is that when I tap on one of those images, that image should show up at the top of the screen. To put it in other words, you all know Instagram posts, right. When you go to your profile page and click one of the images from the grid view, exactly that image pops up on the top of your screen and you can scroll up and down to see the other images as well.
child: new StaggeredGridView.countBuilder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
crossAxisCount: 4,
mainAxisSpacing: 3,
crossAxisSpacing: 3,
staggeredTileBuilder: (int index) =>
new StaggeredTile.count(2, index.isEven ? 2 : 3),
itemCount: _posts.length,
itemBuilder: (BuildContext context, int index) {
Post post = _posts[index];
List<PostView> postViews = [];
_posts.forEach((post) {
postViews.add(PostView(
currentUserId: widget.currentUserId,
post: post,
author: _profileUser,
));
});
return GestureDetector(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SingleChildScrollView(
child: ListView.builder(
padding: EdgeInsets.only(top: 0),
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: postViews.length,
itemBuilder:
(BuildContext context, int index) {
return Column(children: postViews);
},
),
),
),
),
child: Container(
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.all(
Radius.circular(15),
),
),
child: ClipRRect(
borderRadius:
BorderRadius.all(Radius.circular(7)),
child: Image(
image:
CachedNetworkImageProvider(post.imageUrl),
fit: BoxFit.cover,
),
),
),
);
},
),
When I am clicking on one of the images, I am getting the list of images starting from beginning instead of that exact image.
Try to implement scroll_to_index listview in your second page when pressing the image of your grid, when you press image, pass index to second page and jump to that index image after build:
ListView(
scrollDirection: scrollDirection,
controller: controller,
children: randomList.map<Widget>((data) {
final index = data[0];
final height = data[1];
return AutoScrollTag(
key: ValueKey(index),
controller: controller,
index: index,
child: Text('index: $index, height: $height'),
highlightColor: Colors.black.withOpacity(0.1),
);
}).toList(),
)

Make the ListView.builder() show a fraction of the next (or previous) element

How can Make the ListView.builder() show a fraction of the next (or previous) element.
I have a ListView.builder() and it works fine but I want the user to know that there is a scrolling functionality and that they need to scroll.
How can achieve that?
My output:-
Expected output:-
How can achieve that?
Here is my code
return FutureBuilder(
future: categories,
builder: (BuildContext context, AsyncSnapshot snapshot) {
return ListView.builder(
itemCount: snapshot.data.length,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return GestureDetector(
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Container(
child: Padding(
padding:
const EdgeInsets.fromLTRB(16.0, 7.0, 16.0, 10.0),
child: Text(
snapshot.data[index].name,
style: TextStyle(
color: Colors.white,
fontSize: 18.0,
fontWeight: FontWeight.bold),
),
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25.0),
color: colors[index],
),
),
),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Posts(
type: PostsFetchByType.categories,
categoryOrTagIds: [snapshot.data[index].id],
))),
);
});
});
Create a scrollcontroller with an initial offfset:
scrollController = ScrollController(
initialScrollOffset: 10 // put your value here
);
then add it to your ListViewBuilder:
return ListView.builder(
...
controller: scrollController,
...
)
But since you want to show that it is scrollable, you can also have a look at adding scrolling bar by wrapping ListViewBuilder as follows:
Scrollbar(
child: ListView.builder(...),
)

Flutter ListView.builder not working in alert dialog

I want to display item list in alert dialog, for payment confirmation.
but it's not working, i tried many solutions.
AlertDialog(
titlePadding: EdgeInsets.all(0),
contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
title: Text("Heading"),
content: ListView.builder(
shrinkWrap: true,
itemCount: items.length,
itemBuilder: (ctx, i) {
return getRowWidget(i);
}),
);
This will solve your problem, Add Container with width.
showDialog(
context: context,
builder: (context) => AlertDialog(
titlePadding: EdgeInsets.all(0),
contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
title: Text("Heading"),
content: Container(
width: double.maxFinite,
child: ListView.builder(
shrinkWrap: true,
itemCount: items.length,
itemBuilder: (ctx, i) {
return Text(items[i].toString());
}),
),
),
);
Use this code.
showDialog(
context: context,
builder: (context) => AlertDialog(
titlePadding: EdgeInsets.all(0),
contentPadding:
EdgeInsets.symmetric(horizontal: 10, vertical: 0),
title: Text("Heading"),
content: Container(
height: 100,
child: ListView.builder(
shrinkWrap: true,
itemCount: 1,
itemBuilder: (ctx, i) {
return Text("text");
}),
),
),
);

clip padding while scrolling on list view in flutter

I have used clipToPadding in android to clip the padding while scrolling horizontally and vertically. Is there any specific attribute like clipToPadding in flutter? The behavior would look alike:
ListView.separated(
padding: EdgeInsets.all(16),
scrollDirection: Axis.horizontal,
separatorBuilder: (context, index) => SizedBox(
width: 8,
),
itemBuilder: (BuildContext context, int index) {
return Text(data[index].name);
},
itemCount: data.length,
)
I'm not a native android dev, but if I did understand right the "clipToPadding" option, you just want to remove padding from the ListView and add padding around it.
Container(
height: 100.0,
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: ListView.separated(
scrollDirection: Axis.horizontal,
separatorBuilder: (context, index) => SizedBox(
width: 8,
),
itemBuilder: (BuildContext context, int index) {
return AspectRatio(
aspectRatio: 1.0,
child: Container(
color: Colors.grey[300],
child: Center(child: Text(index.toString())),
),
);
},
itemCount: 20,
),
),
OR using Container (it's just to set max height for the listview) + separate Padding:
Container(
height: 100.0,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: ListView.separated(
scrollDirection: Axis.horizontal,
separatorBuilder: (context, index) => SizedBox(
width: 8,
),
itemBuilder: (BuildContext context, int index) {
return AspectRatio(
aspectRatio: 1.0,
child: Container(
color: Colors.grey[300],
child: Center(child: Text(index.toString())),
),
);
},
itemCount: 20,
),
),
),