showModalBottomSheet adaptive size Flutter - flutter

I have the next problem, having a little number of children allows users to scroll even though there is an empty space
Future<void> buildScrollableSheet([Widget? header]) {
return showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) => makeDismissible(
child: DraggableScrollableSheet(
initialChildSize: 0.3,
maxChildSize: 0.9, // this one should be adaptive
builder: (_, controller) => Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(
top: Radius.circular(25),
),
),
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
// crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Padding(
padding: EdgeInsets.all(24),
child: Center(
child: Text(
'My header',
style: TextStyle(
color: Color(0xff757575),
fontSize: 14,
),
),
),
),
Flexible(
child: Material(
color: Colors.white,
child: ListView(
shrinkWrap: true,
controller: controller,
children: [
SimpleHeader(
title: 'title',
text: 'text',
),
SimpleHeader(
title: 'title',
text: 'text',
),
SimpleHeader(
title: 'title',
text: 'text',
),
],
),
),
),
],
),
),
),
),
);
}
Here you can see maxChildSize is being set as 0.9 which is fine with a lot of children inside ListView, but in this case, there are only 3 elements and I want to prevent scrolling to full size, also it would be great to set initialChildSize to childs size, so if I have a huge list of items it would always open full.
Thank you!

Related

Columns shift when SingleChildScrollView is added Flutter

Need help. I have created a column on the page inside which there are 2 more columns, so I moved the buttons that are at the bottom to the very bottom so that they are always at the bottom of the screen. But when I add a SingleChildScrollView to make the page scroll, the space between the columns disappears and the bottom buttons move under other widgets. How can I solve the problem so that when adding a SingleChildScrollView, there is an empty space and the buttons remain at the very bottom of the screen?
body
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: [
const SizedBox(height: 121.0),
BackStepWidget(
text: 'Balance: $coins',
textStyle: constants.Styles.largeHeavyTextStyleWhite,
),
const Text(
'Buy JoinCoins',
style: constants.Styles.bigHeavyTextStyleWhite,
),
const Image(
image: AssetImage('assets/images/image.png'),
),
const Text('I Want To Buy',
style: constants.Styles.smallBoldTextStyleWhite),
const SizedBox(height: 10),
const CoinsCounterWidget(),
const SizedBox(height: 10),
const Text('JoynCoins',
style: constants.Styles.smallBoldTextStyleWhite),
],
),
Column(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 24),
child: DefaultButtonGlow(
text: 'Buy me JoynCoins for 100% battery.',
color: constants.Colors.greyLight.withOpacity(0.4),
textStyle: constants.Styles.buttonTextStyle,
shadowColor: Colors.transparent,
borderColor: constants.Colors.purpleMain,
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return const DefaultAlertDialog(
text:
'Please set a payment method for buying JoynCoins.',
);
},
);
},
),
),
Padding(
padding: const EdgeInsets.only(bottom: 47),
child: DefaultButtonGlow(
text: 'Buy Now ',
color: constants.Colors.purpleMain,
textStyle: constants.Styles.buttonTextStyle,
shadowColor: constants.Colors.purpleMain,
borderColor: constants.Colors.purpleMain,
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return const DefaultAlertDialog(
text: "You'r about to buy",
isText2: true,
text2: '2500 JoynCoins',
);
});
},
),
)
],
)
],
),
));
Added SingleChildScrollView
Without SingleChildScrollView
You can simplify this code to understand the issue. MainAxisAlignment.spaceBetween will provide maximum spaces between widgets.
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("top"),
Text("bottom"),
],
),
Once you wrapped with SingleChildScrollView, Column takes minimum height for its children and become,
You can use SizedBox to provide space between items. You can use LayoutBuidler that I've posted on your previous question. For this I am using MediaQuery
body: SingleChildScrollView(
child: Column(
children: [
Text("top"),
SizedBox(
height: MediaQuery.of(context).size.height * .4,
), // you custom height
Text("bottom"),
],
),
),
Use SizedBox in between Columns or use the following inside Singlechildscrollview
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,

How to make ExpansionTile scrollable when end of screen is reached?

In the project I'm currently working on, I have a Scaffold that contains a SinlgeChildScrollView. Within this SingleChildScrollView the actual content is being displayed, allowing for the possibility of scrolling if the content leaves the screen.
While this makes sense for ~90% of my screens, however I have one screen in which I display 2 ExpansionTiles. Both of these could possibly contain many entries, making them very big when expanded.
The problem right now is, that I'd like the ExpansionTile to stop expanding at latest when it reaches the bottom of the screen and make the content within the ExpansionTile (i.e. the ListTiles) scrollable.
Currently the screen looks like this when there are too many entries:
As you can clearly see, the ExpansionTile leaves the screen, forcing the user to scroll the actual screen, which would lead to the headers of both ExpansionTiles disappearing out of the screen given there are enought entries in the list. Even removing the SingleChildScrollView from the Scaffold doesn't solve the problem but just leads to a RenderOverflow.
The code used for generating the Scaffold and its contents is the following:
class MembershipScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() => _MembershipScreenState();
}
class _MembershipScreenState extends State<MembershipScreen> {
String _fontFamily = 'OpenSans';
Widget _buildMyClubs() {
return Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Color(0xFFD2D2D2),
width: 2
),
borderRadius: BorderRadius.circular(25)
),
child: Theme(
data: ThemeData().copyWith(dividerColor: Colors.transparent),
child: ExpansionTile(
title: Text("My Clubs"),
trailing: Icon(Icons.add),
children: getSearchResults(),
),
)
);
}
Widget _buildAllClubs() {
return Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Color(0xFFD2D2D2),
width: 2
),
borderRadius: BorderRadius.circular(25)
),
child: Theme(
data: ThemeData().copyWith(dividerColor: Colors.transparent),
child: SingleChildScrollView(
child: ExpansionTile(
title: Text("All Clubs"),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.add)
],
),
children: getSearchResults(),
),
)
)
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
extendBody: true,
body: AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light,
child: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Stack(
children: <Widget>[
Container(
height: double.infinity,
width: double.infinity,
decoration: BoxDecoration(
gradient: kGradient //just some gradient
),
),
Center(
child: Container(
height: double.infinity,
constraints: BoxConstraints(maxWidth: 500),
child: SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
padding: EdgeInsets.symmetric(horizontal: 40.0, vertical: 20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Clubs',
style: TextStyle(
fontSize: 30.0,
color: Colors.white,
fontFamily: _fontFamily,
fontWeight: FontWeight.bold),
),
SizedBox(
height: 20,
),
_buildMyClubs(),
SizedBox(height: 20,),
_buildAllClubs()
],
),
),
),
),
],
),
)
),
);
}
List<Widget> getSearchResults() {
return [
ListTile(
title: Text("Test1"),
onTap: () => print("Test1"),
),
ListTile(
title: Text("Test2"),
onTap: () => print("Test2"),
), //etc..
];
}
}
I hope I didn't break the code by removing irrelevant parts of it in order to reduce size before posting it here. Hopefully, there is someone who knows how to achieve what I intend to do here and who can help me with the solution for this.
EDIT
As it might not be easy to understand what I try to achieve, I tried to come up with a visualization for the desired behaviour:
Thereby, the items that are surrounded with dashed lines are contained with the list, however cannot be displayed because they would exceed the viewport's boundaries. Hence the ExpansionTile that is containing the item needs to provide a scroll bar for the user to scroll down WITHIN the list. Thereby, both ExpansionTiles are visible at all times.
Try below code hope its help to you. Add your ExpansionTile() Widget inside Column() and Column() wrap in SingleChildScrollView()
Refer SingleChildScrollView here
Refer Column here
You can refer my answer here also for ExpansionPanel
Refer Lists here
Refer ListView.builder() here
your List:
List<Widget> getSearchResults = [
ListTile(
title: Text("Test1"),
onTap: () => print("Test1"),
),
ListTile(
title: Text("Test2"),
onTap: () => print("Test2"),
), //etc..
];
Your Widget using ListView.builder():
SingleChildScrollView(
padding: EdgeInsets.all(20),
child: Column(
children: [
Card(
child: ExpansionTile(
title: Text(
"My Clubs",
),
trailing: Icon(
Icons.add,
),
children: [
ListView.builder(
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return Column(
children: getSearchResults,
);
},
itemCount: getSearchResults.length, // try 50 length just testing
),
],
),
),
],
),
),
Your Simple Widget :
SingleChildScrollView(
padding: EdgeInsets.all(20),
child: Column(
children: [
Card(
child: ExpansionTile(
title: Text(
"My Clubs",
),
trailing: Icon(
Icons.add,
),
children:getSearchResults
),
),
],
),
),
Your result screen ->

key board hinding screen in flutter

here is code[enter image description here[][1]][1]
hey I am developing a new app that has a comment section show I put Text field in bottom because of better view but I am having a problem whenever I open my keyboard my half screen gets hide, this is very
bad for user Interface so here I need your help, And when I make resizeToAvoidBottomInset false text field get hide behind keyboard
appBar: AppBar(
elevation: 0.0,
title: Text(
"Comments",
style: TextStyle(color: Colors.black),
),
),
body: Column(children: [
Expanded(
child: Obx(
() => ListView.builder(
itemCount: controller.comments.length,
itemBuilder: (BuildContext context, int index) {
return Comment(
comment: controller.comments[index]['comment'],
userid: controller.comments[index]['userid']);
}),
),
),
Spacer(),
Container(
height: 50,
child: CupertinoTextField(
controller: controller.postComment,
padding: const EdgeInsets.all(8),
prefix: IconButton(
onPressed: () {},
icon: Icon(Icons.emoji_emotions),
),
// decoration: BoxDecoration(border: Border.all()),
suffix: IconButton(
icon: Icon(Icons.send),
onPressed: () {
controller.addComment(
args, FirebaseAuth.instance.currentUser.uid);
},
),
placeholder: "Enter a Comment",
),
)
]),
); ```
[1]: https://i.stack.imgur.com/FER2u.png
I believe you can use SingleChildScrollView if you want to make your content inside column scrollable when keyboard is shown. Here is the example of usage:
SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
height: 250,
color: Colors.red[600],
child: const Center(child: Text('Entry A')),
),
Container(
height: 250,
color: Colors.red[500],
child: const Center(child: Text('Entry B')),
),
Container(
height: 250,
color: Colors.yellow[100],
child: const Center(child: Text('Entry C')),
),
],
),
)

Flutter UI List Item

I am using the below code but not able to achieve the desired result, I am new to the flutter world so let me know where to improve to get the desired result. Here is the source code of what I have done.
return Expanded(
child: GridView.builder(
controller: _scrollController,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount: albumList.length,
itemBuilder: (BuildContext context, int index) {
return buildRow(index);
},
),
);
Widget buildRow(int index) {
return AlbumTile(
index: index,
albumList: albumList,
deleteAlbum: _deleteAlbum,
);
}
This the Album Tile
class AlbumTile extends StatelessWidget {
AlbumTile(
{Key key,
#required this.index,
#required this.albumList,
#required this.deleteAlbum})
: super(key: key);
final int index;
final List<Album> albumList;
final Function deleteAlbum;
#override
build(BuildContext context) {
String thumb;
if (albumList.elementAt(index).thumbUrl != "") {
thumb = WEBSERVICE_IMAGES +
albumList.elementAt(index).userId.toString() +
'/' +
albumList.elementAt(index).id.toString() +
'/' +
albumList.elementAt(index).thumbUrl;
} else {
thumb = "https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823__340.jpg";
}
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
new AlbumPage(tabIndex: index, albumList: albumList),
),
);
},
child: Container(
// height of the card which contains full item
height: MediaQuery.of(context).size.height * 0.4,
width: MediaQuery.of(context).size.width * 0.28,
// this is the background image code
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
// url is my own public image url
image: NetworkImage(thumb),
),
borderRadius: BorderRadius.circular(12.0)),
// this is the item which is at the bottom
child: Align(
// aligment is required for this
alignment: Alignment.bottomLeft,
// items height should be there, else it will take whole height
// of the parent container
child: Container(
padding: EdgeInsets.only(left: 10.0, right: 0.0),
height: MediaQuery.of(context).size.height * 0.1,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Text() using hard coded text right now
Text(albumList.elementAt(index).name,
style: TextStyle(
fontSize: 18.5,
color: Colors.white,
fontWeight: FontWeight.w500)),
SizedBox(height: 3.0),
Text(albumList.elementAt(index).photos.toString() +' photos',
style: TextStyle(
fontSize: 12.5,
color: Colors.white,
fontWeight: FontWeight.w500))
],
),
),
// pop-up item
PopupMenuButton(
icon: Icon(Icons.more_vert, color: Colors.white),
itemBuilder: (_) => <PopupMenuItem<String>>[
new PopupMenuItem<String>(
child: Row(
children: <Widget>[
Icon(Icons.delete),
Text(
'Delete Album',
),
],
),
value: 'Delete',
),
],
onSelected: (value) {
deleteAlbum(albumList.elementAt(index).id, index);
},
),
],
),
),
),
),
);
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
new AlbumPage(tabIndex: index, albumList: albumList),
),
);
},
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Stack(
fit: StackFit.loose,
children: <Widget>[
ClipRRect(
borderRadius: new BorderRadius.circular(8.0),
child: FadeInImage.assetNetwork(
height: 1000,
placeholder: kPlaceHolderImage,
image: thumb,
fit: BoxFit.cover,
),
),
Align(
alignment: Alignment.bottomLeft,
child: Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(8, 0, 0, 0),
child: Text(
albumList.elementAt(index).name,
style: TextStyle(
color: Colors.white,
fontSize: 18.5,
),
textAlign: TextAlign.left,
),
),
),
PopupMenuButton(
icon: ImageIcon(
AssetImage("graphics/horizontal_dots.png"),
color: Colors.white,
),
itemBuilder: (_) => <PopupMenuItem<String>>[
new PopupMenuItem<String>(
child: Row(
children: <Widget>[
Icon(Icons.delete),
Text(
'Delete Album',
),
],
),
value: 'Delete',
),
],
onSelected: (value) {
deleteAlbum(albumList.elementAt(index).id, index);
}),
],
),
),
],
),
),
);
}
}
Thank you in advance.
Welcome to the flutter. Amazing platform to start you career on building cross-platform mobile applications.
My code will look a bit different to you, but trust me, this will work out for you.
Please note: You need to change some parts, like changing the image url for NetworkImage(), onTap function, Text() content etc. But not much changes in the Whole Widget code. So please look for those, and make changes accordingly. You will get there :)
GestureDetector(
onTap: () => print('Works!'), // <-- onTap change, I have used print()
child: Container(
// height of the card which contains full item
height: MediaQuery.of(context).size.height * 0.4,
width: MediaQuery.of(context).size.width * 0.28,
// this is the background image code
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
// url is my own public image url
image: NetworkImage('https://cdn.pixabay.com/photo/2015/12/01/20/28/road-1072823__340.jpg')
),
borderRadius: BorderRadius.circular(12.0)
),
// this is the item which is at the bottom
child: Align(
// aligment is required for this
alignment: Alignment.bottomLeft,
// items height should be there, else it will take whole height
// of the parent container
child: Container(
padding: EdgeInsets.only(left: 10.0, right: 0.0),
height: MediaQuery.of(context).size.height * 0.1,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Text() using hard coded text right now
Text('Potraits', style: TextStyle(fontSize: 20.0, color: Colors.white, fontWeight: FontWeight.w500)),
SizedBox(height: 3.0),
Text('150 photos', style: TextStyle(fontSize: 17.0, color: Colors.white, fontWeight: FontWeight.w500))
]
)
),
// pop-up item
PopupMenuButton(
icon: Icon(Icons.more_vert, color: Colors.white),
itemBuilder: (_) => <PopupMenuItem<String>>[
new PopupMenuItem<String>(
child: Row(
children: <Widget>[
Icon(Icons.delete),
Text(
'Delete Album',
),
],
),
value: 'Delete',
),
],
onSelected: (value) {
//your function
}
)
]
)
)
)
)
)
Result
EDITS FOR WHOLE UI
So, the change required is in your buildRow Widget. You just need to give some paddings on your sides, and you are pretty much solid. Let me know
Widget buildRow(int index) {
return Padding(
padding: EdgeInsets.all(10.0),
child: AlbumTile(
index: index,
albumList: albumList,
deleteAlbum: _deleteAlbum,
)
);
}
And if you are unsatisfied with the spacings, just keep playing with the EdgeInsets painting class. I hope that helps. Please let me know. :)

How to handle Login Screen scroll in Flutter?

I am new to Flutter where I am trying to create a Login Screen, but I am not able to handle proper scroll of an field. Below is the code I had written.The main problem is that the text form field go above image which should not happen when it push up.
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Image.asset(
"assets/ic_login_stack.png",
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
fit: BoxFit.cover,
),
Scaffold(
key: scaffoldKey,
backgroundColor: Colors.transparent,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
),
body: Center(
child: SingleChildScrollView(
padding: EdgeInsets.only(left: 24.0, right: 24.0),
child: Column(
children: <Widget>[
SizedBox(height: 55.0),
Form(key: formKey, child: _getUIForm()),
SizedBox(
width: double.infinity,
height: 50,
child: GestureDetector(
child: RaisedButton(
child: Text(AppLocalizations.of(context).buttonText,
style: TextStyle(
color: Colors.white, fontSize: 18.0)),
elevation: 5.0,
color: Color(0xffE9446A),
//onPressed: _submit,
onPressed: () => {
/*Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CompanyWall()
)
)*/
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) => CompanyWall()),
(r) => false)
},
),
)),
SizedBox(height: 20.0),
GestureDetector(
onTap: () =>
Navigator.of(context).pushNamed(ResetPassword.tag),
child: Text(
AppLocalizations.of(context).forgotPasswordText,
style: TextStyle(
decoration: TextDecoration.underline,
color: Colors.grey[800],
fontSize: 16.0),
),
),
SizedBox(height: 30.0),
GestureDetector(
onTap: () =>
Navigator.of(context).pushNamed(SignUpScreen.tag),
child: Text(AppLocalizations.of(context).signUpFreeText,
style: TextStyle(
color: Color(0xffE9446A),
fontSize: 18.0,
fontWeight: FontWeight.bold)),
),
],
),
),
),
)
],
);
}
_getUIForm() {
Multiple Text Form Feild
}
And below are the out put I obtained while running code.How should I handle scroll that textformfeild should remain below the logo.
You are using a Stack with 2 children - the Image and the scrolling content. The image is outside the scrolling content so it will not change its position as you scroll.
If you want the image to scroll along with the content, change your layout so that your Stack is within the SingleChildScrollView. It should end up roughly like so:
Scaffold -> SingleChildScrollView -> Stack -> [Image, Column]
In the scaffold add this
return Scaffold(
resizeToAvoidBottomPadding: false, // <-- add this
);