Flutter Widget In Detail: Scaffold
Exploring Scaffold Widget: A blog explaining what is Scaffold, how to use it, and examples. An in-depth guide for newbie and senior developers.

Search for a command to run...
Exploring Scaffold Widget: A blog explaining what is Scaffold, how to use it, and examples. An in-depth guide for newbie and senior developers.

No comments yet. Be the first to comment.
In this series, I am going to explain all the important Flutter widgets in detail.
Detailed Explanation of MaterialApp Widget
Lessons from Code, Content, and Consistency

Reliability basics: Outbox pattern + why it matters

Introducing Kafka/Redpanda + move to event-driven workflow

Connect Orders โ Inventory (first working service-to-service flow)

Inventory service + gRPC + proto contracts


AppBar, BottomNavigationBar, Drawer, FloatingActionButton, BottomSheet, that we can use in our app.
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text("๐ข I'dont have Scaffold")
);
}
}

class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text("๐ I am inside Scaffold")
)
);
}
}

body :Widget as an input.body has the primary content that has to be shown on the screen.
Center widget.Scaffold(
body: Center(
child: Text("๐ Center of the Scaffold")
)
);

Text inside the Container, it will only take the height and width of its child widget :Scaffold(
body: Center(
child: Container(
color: Colors.green,
child: Text(" ๐ค Expand me")
)
)
);

Scaffold(
body: SizedBox.expand(
child: Container(
alignment: Alignment.center,
color: Colors.green,
child: Text("๐ฅณ Yay!! I'm Expanded")
),
)
);

Column widgets, normally it should fit on the screen. But content may overflow from the Column.
Scaffold(
body: ListView(
children: [
Container(
width: 200,
height: 150,
color: Colors.green,
),
// other widgets
],
)
);

backgroundColor :Color value inside the backgroundColor property.ThemeData.scaffoldBackgroundColor.Scaffold(
backgroundColor: Colors.purple,
body: // widget
);

floatingActionButton :floating above the body, In the bottom-right cornerScaffold(
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: (){},
),
body: // widget
);

child property of FloatingActionButton is used to give any kind of widget as a child of FloatingActionButton.onPressed property provides a callback that is called when the button is pressed.floatingActionButtonLocation :floatingActionButton should go.floatingActionButton is place at bottom-right corner.floatingActionButton.
Scaffold(
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
body: // widget
)

floatingActionButtonAnimator :floatingActionButton from one floatingActionButtonLocation to another.FloatingActionButtonAnimatordefines :Offset of the FloatingActionButton between old and new floatingActionButtonLocation.Animation to scale the FloatingActionButton during the transition.Animation to rotate the FloatingActionButton during the transition.FloatingActionButtonAnimator has one constant called scaling which moves the FloatingActionButton by scaling out and then in at a new FloatingActionButtonLocation.appBar :AppBar() as an input.title, actions, elevation, backgroundColor etc.Scaffold(
appBar: AppBar(
title: Text("Widget In Detail"),
backgroundColor: Colors.deepOrangeAccent,
),
body: // widget
);

bottomNavigationBar :BottomNavigationBar for navigation, positioned at the bottom of the Scaffold body.bottomNavigationBar, but Flutter provides us a built-in BottomNavigationBar.Scaffold(
body: Container(),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
fixedColor: Colors.deepOrange,
items: [
BottomNavigationBarItem(
title: Text("Home"),
icon: Icon(Icons.home),
),
BottomNavigationBarItem(
title: Text("Search"),
icon: Icon(Icons.search),
),
BottomNavigationBarItem(
title: Text("Add"),
icon: Icon(Icons.add_box),
),
],
onTap: (int index){
setState(() {
_currentIndex = index;
});
},
),
);

bottomSheet:bottomSheet : BottomSheet widget itself is rarely used directly. Because we can't open or close it by swiping up or down. It's static.Scaffold(
bottomSheet: BottomSheet(
onClosing: (){},
builder: (_){
return Container(
width: MediaQuery.of(context).size.width,
height:150,
color:Colors.green,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Count in BottomSheet $_bottomSheetCounter"),
RaisedButton(
child: Icon(Icons.add),
onPressed:(){
setState((){
_bottomSheetCounter++;
});
}
)
],
)
);

ScaffoldState.showBottomSheet or Scaffold.bottomSheet, and a modal bottom sheet with showModalBottomSheet.persistentBottomSheet :GlobalKey of type ScaffoldState. And pass it to the Scaffold's key propertyfinal _scaffoldKey = new GlobalKey<ScaffoldState>();
Scaffold(
key: _scaffoldKey
)
Scaffold(
key:_scaffoldKey,
body: Center(
child: RaisedButton(
onPressed: _showPersistentBottomSheet,
child: Text("Persistent"),
),
)
)
VoidCallback of _showPersistentBottomSheet and assign it to the actual function that will trigger the bottomSheet.VoidCallback? _showPersBottomSheetCallBack;
@override
void initState() {
super.initState();
_showPersBottomSheetCallBack = _showBottomSheet;
}
void _showBottomSheet() { // }
_showBottomSheet function.void _showBottomSheet() {
setState(() {
_showPersBottomSheetCallBack = null; // We don't want to press button again if the sheet already opened That's why we are disabling the button.
});
_scaffoldKey.currentState
!.showBottomSheet((context) {
return Container(
height: 200.0,
color: Colors.deepOrange,
child: Center(
child: Text("I'm Persistent"),
),
);
})
.closed
.whenComplete(() {
if (mounted) {
// If our sheet is not visible then we are again attaching the `_showBottomSheet` function to `_showPersBottomSheetCallBack ` as we did in `initState`
setState(() {
_showPersBottomSheetCallBack = _showBottomSheet;
});
}
});
}

showModelBottomSheet :showModelBottomSheet function which is in-built in flutter and attach with any button, you are ready to go.
-void _showModalSheet() {
showModalBottomSheet(
context: context,
builder: (builder) {
return Container(
color: Colors.greenAccent,
child: new Center(
child: Text("I'm ModalSheet"),
),
);
});
}

drawer :Panel displayed on the left or right side of the body.drawer takes Drawer widget as input.Drawer too.Scaffold(
appBar: AppBar(),
drawer: Drawer(
elevation: 16.0,
child: Column(
children: <Widget>[
UserAccountsDrawerHeader(
accountName: Text("Dhruv"),
accountEmail: Text("nakumdhruv123@gmail.com"),
currentAccountPicture: CircleAvatar(
backgroundImage: NetworkImage("https://media-exp1.licdn.com/dms/image/C4D03AQHDlYNK0WgLFA/profile-displayphoto-shrink_400_400/0/1621524948952?e=1634169600&v=beta&t=_fPR4KDunI_mvH0YCaa9T_aj1Fo0A19DlTbF7n_IdBM"),
),
),
ListTile(
title: new Text("All Inboxes"),
leading: new Icon(Icons.mail),
),
Divider(
height: 0.1,
),
ListTile(
title: new Text("Primary"),
leading: new Icon(Icons.inbox),
),
ListTile(
title: new Text("Social"),
leading: new Icon(Icons.people),
),
ListTile(
title: new Text("Promotions"),
leading: new Icon(Icons.local_offer),
)
],
),
),
body: Container()
);

drawerEdgeDragWidth:0.0 and see what happenScaffold(
drawerEdgeDragWidth: 0,
)

Scaffold(
drawerEdgeDragWidth: 150,
)

drawerScrimColor :Colors.black54Scaffold(
drawerScrimColor: Colors.red.shade300,
)

drawerEnableOpenDragGesture :drawer by dragging.false, the drawer will no longer open when the user will swipe from left-to-right or right-to-left.true.Scaffold(
drawerEnableOpenDragGesture: false,
)

onDrawerChanged :Drawer is opened or closedScaffold(
onDrawerChanged: (_){
print("Drawer $_");
},
)

endDrawer :drawer, but instead the panel/drawer is on the right side of the app.Scaffold(
endDrawer: Drawer(
elevation: 16.0,
child: Column(
children: <Widget>[
UserAccountsDrawerHeader(
accountName: Text("Dhruv"),
accountEmail: Text("nakumdhruv123@gmail.com"),
currentAccountPicture: CircleAvatar(
backgroundImage: NetworkImage(url),
),
),
// Drawer content
],
),
),
)

endDrawerEnableOpenDragGesture:drawerEnableOpenDragGesture but for the endDrawerfalse, the drawer will no longer open when the user will swipe from right-to-left or left-to-right.true.onEndDrawerChanged :onDrawerChanged, except it is for endDrawerScaffold(
onEndDrawerChanged: (_){
print("Drawer $_");
},
)
extendBody :true, and bottomNavigationBar is specified, then the body extends to the bottom of the Scaffold. Instead of only extending to the top bottomNavigationBar.false, and bottomNavigationBar is specified, then the body will not extend to the bottom of the Scaffold. And only extends to the top bottomNavigationBar.falseextendBody: trueScaffold(
extendBody: true,
bottomNavigationBar: BottomNavigationBar(
// navigation items
)
body: // items
)

extendBody: false (Default)Scaffold(
extendBody: false,
bottomNavigationBar: BottomNavigationBar(
// navigation items
)
body: // items
)

extendBodyBehindAppBar :AppBar.AppBar should have transparent backgroundColorextendBodyBehindAppBar : trueScaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(backgroundColor: Colors.transparent,)
body: // items
)

extendBodyBehindAppBar : falseScaffold(
extendBodyBehindAppBar: false,
appBar: AppBar(backgroundColor: Colors.transparent,)
body: // items
)

If you are using
ListVieworGridViewmake sure to havepadding: EdgeInsets.only(top: 0), to see expected results.
persistentFooterButtons :Scaffold.persistentFooterButtons are rendered above the bottomNavigationBar but below the body.Scaffold(
body: Container(
color: Colors.white,
child: Center(child: Text("Persistent Footer Buttons"),),
),
persistentFooterButtons: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
FlatButton(
onPressed: () {},
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Icon(Icons.home),
new Text('Home'),
],
),
),
FlatButton(
onPressed: () {},
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Icon(Icons.search),
new Text('Search'),
],
),
),
FlatButton(
onPressed: () {},
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Icon(Icons.person),
new Text('Profile'),
],
),
),
],
),
],
);

resizeToAvoidBottomInset :true the body and the scaffold's floating widgets should size themselves to avoid the onscreen keyboard.scaffold, the body can be resized to avoid overlapping the keyboard, which prevents widgets inside the body from being obscured by the keyboard.resizeToAvoidBottomInset : false : Scaffold(
resizeToAvoidBottomInset: false,
body: // Content
)

resizeToAvoidBottomInset : true : Scaffold(
resizeToAvoidBottomInset: true,
body: // Content
)

primary :scaffold is being displayed at the top of the screen.appBar will be extended by the height of the screen's status bar, i.e. the top padding for MediaQuery.AppBar.primary, is true.primary: false
primary: true
restorationId :Flutter State Restoration in MaterialApp's BlogThank you for reading

Previous Widget: MaterialApp