Columns shift when SingleChildScrollView is added Flutter - 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,

Related

flutter Specify height of card in listview.builder

I want the cards built in a listview.builder, to have a height of 150.
What currently happens:
Currently, with my code, here's what gets built. Instead of the default height, I want to explicitly set my own card height, say, 150
What I have tried:
Isn't using SizedBox enough to get the height I want in a listview?
class GamesListState extends State<GamesList> {
#override
Widget build(BuildContext context) {
return MyScaffold(
body: Container(
padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 32),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 32),
const MyHeaderTitle(title: 'Games'),
const SizedBox(height: 40),
Flexible(
child: ListView.builder(
itemCount: list.length,
prototypeItem: ListTile(
title: Text(list.first.values.first),
),
itemBuilder: (context, index) {
return Card(
elevation: 5,
child: SizedBox(
height: 150,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Image.asset('assets/images/logo.png'),
const Text(
'Game name',
style: TextStyle(
fontSize: 10, fontWeight: FontWeight.w700),
),
const Icon(Icons.keyboard_arrow_right)
],
),
),
);
},
)),
],
),
),
);
}
}
Will appreciate any insights as to what I'm doing wrong.
Specify the height of prototypeItem of listView.builder by wrapping it with SizedBox
prototypeItem: ListTile(
title: SizedBox(height: 150, child: Text(list.first.values.first)),
),

How to make list view builder scrollable and set its height space as much as it can take?

I have a problem with ListView. I need to make it scrollable and set its size to max space it can take. Below listView I have a button that should be visible, but the ListView covers it.
I tried solutions from similar topics:
put ListView into SingleChildScrollView
make ListView Expanded
So the problem is:
how to make this listView scrollable?
how can I set its size to max as it can take (I mean it should be between 'List of participants' and Leave button)
how can I attach this button to be always on the bottom of screen, no matter what size of screen I have?
I hope pictures help you to understand what I mean. I also add the code but it is formatted weird, so sorry about that.
Screenshoot from device with above problem:
How it looks on another device and how it should look:
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: const Text('Flutter SDK'),
centerTitle: true),
body: Padding(
padding: const EdgeInsets.all(16),
child: !isInitializedList
? Column(
children: [
TextField(
controller: usernameController,
readOnly: true),
const SizedBox(height: 12),
TextField(
decoration: const InputDecoration(hintText: 'Conference name'),
controller: conferenceNameController),
const SizedBox(height: 12),
ElevatedButton(
onPressed: () async {
// Step 5: Call joinConference()
await joinConference();
},
child: isJoining
? const Text('Joining...')
: const Text('Join the conference')),
const Divider(thickness: 2),
const Text("Join the conference to see the list of participants.")
],
)
: Column(
children: [
Text(
'Conference name: ${conferenceNameController.text}',
style: const TextStyle(fontWeight: FontWeight.w400, fontSize: 16)),
const SizedBox(height: 16),
Column(
children: [
const Align(
alignment: Alignment.centerLeft,
child: Text(
'List of participants:',
style: TextStyle(color: Colors.blue, fontWeight: FontWeight.w600))),
const SizedBox(height: 16),
// Step 7: Display the list of participants
ListView.separated(
separatorBuilder: (BuildContext context, int index) {
return const SizedBox(height: 5);
},
shrinkWrap: true,
itemCount: participants.length,
itemBuilder: (context, index) {
var participant = participants[index];
return Padding(
padding: const EdgeInsets.all(4),
child: Row(children: [
Expanded(
flex: 1,
child: SizedBox(
height: 150,
width: 150,
child: VideoView.withMediaStream(
participant: participant,
mediaStream: participant.streams?.firstWhereOrNull((s) =>
s.type == MediaStreamType.camera),
key: ValueKey('video_view_tile_${participant.id}'))),
),
Expanded(
flex: 1,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Text(
"${participant.info?.name.toString()}"),
Text(
"status: ${participant.status?.name}")
]),
),
)
]),
);
}),
]),
const SizedBox(height: 16),
ElevatedButton(
style: ElevatedButton.styleFrom(primary: Colors.red),
onPressed: () async {
// Step 6: Call leaveConference()
await leaveConference();
},
child: isJoining
? const Text('Leaving...')
: const Text('Leave the conference'))
])
)
);
}
When you want to make list view expand as much as available, you need to wrap it with Expanded widget, by that you tell to column give it space as much as you have, also you need to do this for inside column agin, like this:
Column(
children: [
Text('Conference name: ${conferenceNameController.text}',
style: const TextStyle(fontWeight: FontWeight.w400, fontSize: 16)),
const SizedBox(height: 16),
Expanded(// <--- add this
child: Column(
children: [
const Align(
alignment: Alignment.centerLeft,
child: Text('List of participants:',
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.w600))),
const SizedBox(height: 16),
Expanded( // <--- add this
child: ListView.separated(
separatorBuilder:
...
)
You can make listview scrollable with shrinkwrap parameter inside Listview.builder()

Flutter Alertdialog overflow cutoff

I have a working Alertdialog but I get an overflow error and I can't get rid of it. I have tried flexible and expanded but maybe on the wrong levels.
builder: (BuildContext context) => AlertDialog(
title: const Center(child: Text('Completing task')),
content: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
UnconstrainedBox(
child: Flexible(
child: Column(
children: [
Text('Tag: ' + task.tag),
Text("rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr"),
const SizedBox(height: 10),
const Text('Waiting for NFC'),
const SizedBox(height: 20),
const Center(
child: CircularProgressIndicator(
color: Colors.grey,
),
),
],
),),
),
],
),
The issue here is the long text. If you would like all of the text to display without overflowing the layout, then Flexible is an option. Wrap the Text element with a Flexible when the displayed text could potentially be longer than the width of the view.
Notice that I had to remove some unnecessary elements from the view. Those elements were misplaced/misused for this scenario and were adding to the problem.
There are other ways to handle this, but I like how flexible (pun intended) this option is without having to calculate or guess width/height.
Here is a solution with the code cleaned up a little and using the Flexible on the long text element.
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Center(child: Text('Completing task')),
content: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Tag: P1348'),
Flexible(child: Text("rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr"),),
const SizedBox(height: 10),
const Text('Waiting for NFC'),
const SizedBox(height: 20),
const Center(
child: CircularProgressIndicator(
color: Colors.grey,
),
),
],
)
);
}
);
Container(
child: Text('text',
overflow: TextOverflow.fade,
maxLines: 1,
softWrap: false,
),
width: 50,
),
SizedBox(
width: YourOwnWidth,
child: Text("rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr",style: TextStyle(
overflow: TextOverflow.clip
),),
);
an Easy solution that you can use

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 ->

How to put scroll view inside stack widget in flutter

I am making a flutter application in which i uses body as a stack and in this stack i have two child.One is main body and other is back button which is at top of screen.The first child of stack is scrollview.Here is my build method.
Widget build(BuildContext context) {
return Scaffold(
//debugShowCheckedModeBanner: false,
key: scaffoldKey,
backgroundColor: Color(0xFF5E68A6),
body: Stack(
children: <Widget>[
Container(
margin: const EdgeInsets.fromLTRB(0.0, 10.0 , 0.0 , 0.0 ),
height: double.infinity,
child:CustomScrollView(
slivers: <Widget>[
new Container(
margin: EdgeInsets.all(15.0),
child:Text(getTitle(),
style: TextStyle(fontSize: 20.0,fontWeight: FontWeight.bold,color: Colors.white),
),
),
//middle section
_isLoading == false ?
new Expanded(child: GridView.builder(
itemCount: sub_categories_list.length,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemBuilder: (context, position){
return InkWell(
child: new Container(
//color: Colors.white,
padding: EdgeInsets.all(20),
margin: EdgeInsets.all(10),
height: 130,
width: 130,
child: new Center(
child :
Text(sub_categories_list[position].name,
style: TextStyle(fontSize: 18.0,fontWeight: FontWeight.bold),
)
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(16)),
// border: Border.all(color: Colors.black, width: 3),
),
),
onTap: () {
//write here
// Fluttertoast.showToast(msg: "You clicked id :"+sub_categories_list[position].cat_id.toString());
Navigator.pushNamed(context, '/advicemyself');
},
);
}
))
:
CircularProgressIndicator(),
Container(
margin: EdgeInsets.all(18.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
new Column(
children: <Widget>[
Image.asset('assets/bt1.png'),
Container(
margin: EdgeInsets.all(10.0),
child: Text("FIND HELP",
style: TextStyle(fontSize: 18.0,color: Colors.white),
),
)
],
),
new Column(
children: <Widget>[
Image.asset('assets/bt2.png'),
Container(
margin: EdgeInsets.all(10.0),
child: Text("HOME",
style: TextStyle(fontSize: 18.0,color: Colors.white),
),
)
],
),
new Column(
mainAxisAlignment:MainAxisAlignment.spaceEvenly,
children: <Widget>[
Image.asset('assets/bt3.png'),
Container(
margin: EdgeInsets.all(10.0),
child: Text("CALL 999",
style: TextStyle(fontSize: 18.0,color: Colors.white),
),
)
],
),
],
),
),
],
),
),
Positioned(
left: 10,
top: 30,
child: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => {
//go back
},
color: Colors.white,
iconSize: 30,
),
),
// makeview()
],
),
// This trailing comma makes auto-formatting nicer for build methods.
);
}
I have also tried using SingleChildScrollView but that also does not works.What i am doing wrong here ?
Here is link to the design which i want to make.
https://imgur.com/a/w7nLmKC
The back should be above scroll view so i used stack widget.
Running your sample code, there doesn't seem to be a need for overlapping widgets. Using Stack seems to be unnecessary. One way you could do is by using Column widget, and using Expanded as you see fit.
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Widget(), // back button goes here
CustomScrollView(...),
],
),
);
}
Otherwise, if you really need to use Stack, the scroll function should work fine. I've tried this locally and the Stack widget doesn't interfere with scrolling of Slivers, ListView, and GridView.
Stack(
children: [
/// Can be GridView, Slivers
ListView.builder(),
/// Back button
Container(),
],
),