How to make whole screen scrollable in Flutter? - flutter

I have an issue with the whole screen scrolling in Flutter. Only the Expanded widget is able to scroll on-screen in my app but I want to make the whole screen scrollable. How can I do that? Here is my code e.g.
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
backgroundColor: Colors.white,
appBar: AppBar(
title: Text(
'My App',
style: AppTheme.of(context).title1,
),
elevation: 0,
backgroundColor: Colors.amber,
),
body: Column(
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(10, 20, 10, 0),
child: Column(
. // Padding repeats two more times
.
.
.
Expanded(
child: MyWidget(
myProp1: value1,
myProp2: value2,
myProp3: value3,
myProp4: value4,
myProp5: value5,
myProp6: value6
) // MyWidget
), // Expanded
],
), // Column
); // Scaffold
}
I've tried to wrap Column with SingleChildScrollview widget but it didn't work for me. I guess I can not use Expanded widget in SingleChildScrollview. I also tried to use Container or etc. instead of Expanded and Column widgets but I couldn't solve this issue. Can anybody help me with it?

There is no need to wrap MyWidget with Expanded. Just Change Column into ListView:
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text(
'My App',
),
elevation: 0,
backgroundColor: Colors.amber,
),
body: ListView(
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(10, 20, 10, 0),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 500,
decoration: BoxDecoration(color: Colors.black),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 500,
decoration: BoxDecoration(color: Colors.black),
),
)
],
))
],
), // Column
); // Scaffold
}

You also can use the SingleChildScroll view as Child of Expanded widget will work fine

Related

how to takes a entire available space in column in flutter

I will explain with simple examble,
class Demo1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Column(
children: [
Flexible(
child: ListView(
shrinkWrap: true,
children: const [
ListTile(
leading: Icon(Icons.image),
title: Text('with shrinkwrap is true'),
trailing: Icon(Icons.delete_forever),
),
])),
Expanded(
child: Container(
color: Colors.green,
)),
],
),
),
);
}
}
Here the green colored container is not filling the remaining space, so how to fill the remaining area?
Thanks in advance
Try below code and just Remove your first Flexible Widget
Column(
children: <Widget>[
ListView(
shrinkWrap: true,
children: const [
ListTile(
leading: Icon(Icons.image),
title: Text('with shrinkwrap is true'),
trailing: Icon(Icons.delete_forever),
),
],
),
Expanded(
child: Container(
color: Colors.green,
),
),
],
),
You can use SingleChildScrollView instead of using ListView with shrinkWrap: true.
class Demo1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Column(
children: [
SingleChildScrollView(
child: Column(
children: const [
ListTile(
leading: Icon(Icons.image),
title: Text('with shrinkwrap is true'),
trailing: Icon(Icons.delete_forever),
),
],
),
),
Expanded(
child: Container(
color: Colors.green,
)),
],
),
),
);
}
}
You may also like CustomScrollView over SingleChildScrollView and shrinkWrap:true.
Both Flexible and Expanded have flex value 1, so they both request 50% of the available space. So the Container child of Expanded takes fills only half space, while the ListView, a child of Flexible, also requests half the space but needs very little space.
You can make Container fill the available space by removing Flexible, so Expanded that wraps Container will get all the available space.

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

Flutter : Change toolbar color in both Android and iOS

I'm very new to flutter, Just trying to create a page where top portion has a red background( stacked) and some text content above it. I want to extend the background colour to the toolbar as well. tried with AnnotatedRegion but it didn't work as expected.Image is attached for reference where toolbar still has a white background, but wanted Red color.
#override
Widget build(BuildContext context) {
return Scaffold(
body: AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light,
child: Column(
children: <Widget>[
SafeArea(
child: Stack(
children: <Widget>[
Container(
width: 500,
height: 350,
// alignment: Alignment.center,
color: Color.fromRGBO(255, 0, 0, 1),
),
Center(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 20.0),
child: Text(
"Lorem ipsum dolor sit amet",
textAlign: TextAlign.center,
style: mainTextStyle,
),
),
),
Container(
padding: new EdgeInsets.symmetric(horizontal: 20.0),
)
],
),
),
Container(
child: Text("Hey Test"),
)
],
),
),
);
}
}
Just add AppBar to the scaffold and backgroundColor to red
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0.0,
backgroundColor: Color.fromRGBO(255, 0, 0, 1),
),
body: Container(
child: //widget
)
);
}
Just wrap your SafeArea widget with Container widget and set color in the Container widget
Like this
Scaffold(
body: Container(
color: Colors.green, /* Set your status bar color here */
child: SafeArea(child: Container(
/* Add your Widget here */
)),
),
);

DropdownButtonHideUnderline custom height

I have a DropdownButtonHideUnderline in my AppBar. I adjusted the color of its container to stand out from the AppBar. I would also like to adjust its height to be less then the AppBar (small padding around the text):
Here is my code:
#override
Widget build(BuildContext context) {
if (widget.appState.isLoading)
return Center(
child: CircularProgressIndicator(),
);
else
return DefaultTabController(
length: 5,
child: Scaffold(
appBar: AppBar(
title: Text("Home"),
actions: <Widget>[
DropdownButtonHideUnderline(
child: Container(
color: Colors.white,
child: DropdownButton(
isDense: true,
value: widget.appState.user.accountNumbers[widget.appState.selectedAccountIndex],
items: widget.appState.user.accountNumbers.map<DropdownMenuItem>((accountNumber) {
return DropdownMenuItem(
child: Text(
accountNumber,
style: Theme.of(context).textTheme.caption,
),
value: accountNumber,
);
}).toList(),
onChanged: (selectedItem) => setState((){
widget.appState.selectedAccountIndex =
widget.appState.user.accountNumbers.indexOf(selectedItem);
}),
),
),
),
IconButton(
...
),
],
bottom: TabBar(
...
),
),
body: TabBarView(
...
),
),
);
}
You can wrap your text widget inside DropdownMenuItem with Container.
//inside DropdownMenuItem
Container(
padding: EdgeInsets.symmetric(vertical: 10.0,),
child: Text(),
)
Thanks for the hints #rmtmckenzie and #yashthakkar1173. What I needed to do was to wrap DropdownButtonHideUnderline in a Container with padding: EdgeInsets.symmetric(vertical: 17.0). That did the trick.

Resize leading widget in flutter AppBar

I am making a custom AppBar that has a larger height than the typical AppBar. I would like to resize the leading widget/icon as well, and take advantage of the automaticallyImplyLeading default behaviors (so the menu icons and back icons are automatically implemented).
This is the solution I thought I would implement:
class AppAppBar extends PreferredSize{
AppAppBar(String title) : super(
preferredSize: Size.fromHeight(56.0),
child: AppBar(
centerTitle: true,
title: Text(title, style: textStyle)
)) {
(child as AppBar).leading =
SizedBox(width: 30.0, height: 30.0, child: (child as AppBar).leading);
}
static const textStyle = TextStyle(fontSize: 32.0);
}
But of course this won't work because (child as AppBar).leading is final.
So in the AppBar below (text size made dramatically larger for illustration purposes), I would like to make the automatically added hamburger icon larger in comparison.
What do you think? Are there solutions for this or should I give up on the automatic icons and add them myself?
Edit: Added an image to show what I mean
You cant because it is a predefined widget.
You can work around it with a Row widget:
Scaffold(
key:_scaffoldKey,
drawer: Drawer(),
appBar: AppBar(
automaticallyImplyLeading: false
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 20, // Your Height
width: 20, // Your width
child: IconButton( // Your drawer Icon
onPressed: () => _scaffoldKey.currentState.openDrawer()),
icon: Icon(Icons.arrow_back, color: Colors.white),
),)
// Your widgets here
],
),
),
)
You need the Key to open the drawer with _scaffoldKey.currentState.openDrawer().
automaticallyImplyLeading: false will prevent the default drawer Icon.
A simple example to demonstrate Raffi Jonas answer
AppBar(
automaticallyImplyLeading: false,
title: Row(
children: [
Expanded(
child: Text('One'),
),
Center(
child: Text('Two'),
),
Expanded(
child: Align(
alignment: Alignment.centerRight,
child: Text('Three'),
),
),
],
),
),
The leading Widget width of AppBar in Flutter can be resized using the leadingWidth property.
For Example :
AppBar(
title: const Text('Title'),
leadingWidth: 50,
leading: Container()
)
What you want is a custom app bar in Flutter. Most people try giving their own widgets in the title argument of an AppBar. But let me show you how to properly do it.
#override
Widget build(BuildContext context) => Scaffold(
appBar: _appBar(),
body: _body(),
);
//Custom AppBar
_appBar() => PreferredSize(
//kToolBarHeight: Default size used by all AppBar widgets in Flutter.
//MediaQuery...: viewPadding.top is StatusBar area. viewPadding.bottom is iPhone bottom bar.
preferredSize: PreferredSize.fromHeight(kToolBarHeight + MediaQuery.of(context).viewPadding.top),
child: Container(
child: Row(
//This will spread Row content evenly across the screen.
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
//Leading Widget
Icon(Icons.home),
//Title
Text("Hello World!"),
//Trailing Widget / Actions
Icon(Icons.home),
],
),
),
);
Widget _body() => Container(
color: Colors.blue,
);
You can set a margin for height or width.
AppBar(
leading: Container(
margin: EdgeInsets.symmetric(vertical: 15),
child: IconButton(
icon: Icon(CupertinoIcons.chevron_left),
onPressed: () {},
),
),
To use a custom appBar leading button, here is the code.
appBar: AppBar(
title: Text('hello'),
// automaticallyImplyLeading: false,
elevation: 0,
leadingWidth: 58,
actions: [
ProfileBar(),
],
leading: Container(
width: 14,
//color: Colors.yellow,
child: Row( // <--- Using row to avoid force resizing of leading
children: [
Padding( // <--- Padding to make it look more nicer
padding: const EdgeInsets.only(left: 24.0),
child: GestureDetector(
onTap: () {
Navigator.of(context).pop();
},
child: SvgPicture.asset( // <-- Using SvgPicture package
'assets/svg/icons/backbtn.svg',
width: 24,
height: 24,
),
),
),
],
),
),
),