Flutter is a cross-platform mobile application development framework that uses a widget-based approach for building UIs. In Flutter, layouts are created using widgets, which are like building blocks that can be combined to create more complex UIs.
Let's take a look at some of the different layout widgets available in Flutter.
Row and Column Widgets:
The Row and Column widgets are used to create horizontal and vertical layouts respectively. They allow you to align widgets either at the start, end, or center of the layout. Here is an example that demonstrates how to use the Row and Column widgets in Flutter:
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'This is a column widget.',
style: TextStyle(
fontWeight: FontWeight.bold,
),),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
const Icon(Icons.ad_units),
const Icon(Icons.access_time_outlined),
const Icon(Icons.add_a_photo_rounded),
],
),
const SizedBox(height: 20),
const Text(
'This is a Row widget.',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 20),
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Image.network("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR4NNNQD8Hsj0EywGnRRXhVsasaOVfXAVvxXM-FxQZnLA&s"),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {},
child: const Text('Button 1'),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(Colors.red),
),
),
ElevatedButton(
onPressed: () {},
child: const Text('Button 2'),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(Colors.red),
),),
ElevatedButton(
onPressed: () {},
child: const Text('Button 3'),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(Colors.red),
),),
],
),
],
),
),
I hope this example helps you understand how to use the Row and Column widgets in Flutter!
Your app will look like this -
In this example, we have a Column widget with three children. The first child is a Text widget that displays the text "This is a column widget." The second child is a Row widget that has three Icon widgets, each displaying a heart icon, and the mainAxisAlignment property is set to MainAxisAlignment.spaceEvenly to evenly distribute the icons across the row.
The third child of the Column widget is another Row widget that contains three ElevatedButton widgets. The mainAxisAlignment property of this row is also set to MainAxisAlignment.spaceEvenly, so the buttons are evenly distributed across the row.
We also use the SizedBox widget to add spacing between the widgets to improve the layout.
Stack Widget:
The Stack widget is used to create overlapping layouts. You can use it to position widgets on top of each other or side by side. Here's a complete example of using the Stack widget in Flutter to create a simple layout:
Stack(
children: <Widget>[
Container(
width: 200,
height: 200,
color: Colors.blue,
),
Positioned(
top: 50,
left: 50,
child: Container(
width: 100,
height: 100,
color: Colors.red,
),
),
Positioned(
top: 100,
left: 100,
child: Container(
width: 100,
height: 100,
color: Colors.green,
),
),
],
),
Output the above code will look like this -
In this example, we create a Stack widget with three children. The first child is a Container widget with a blue color. The second child is a Container widget with a red color, positioned at the top-left corner of the blue container using the Positioned widget. The third child is a Container widget with a green color, positioned at the center of the blue container using the Positioned widget.
The Positioned widget is used to specify the position of the child widgets inside the Stack. We use the top and left properties to position the Container widgets.
I hope this example helps you understand how to use the Stack widget in Flutter!
Expanded and Flexible Widgets:
The Expanded and Flexible widgets are used to create flexible layouts that can adapt to different screen sizes. They allow you to specify the amount of space that each widget should take up in the layout. Here's a complete example of using the Expanded and Flexible widgets in Flutter to create a flexible layout:
Expanded(
flex: 2,
child: Container(
color: Colors.blue,
child: Center(
child: Text(
'Expanded 2',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
),
),
),
Flexible(
flex: 1,
child: Container(
color: Colors.green,
child: Center(
child: Text(
'Flexible 1',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
),
),
),
Flexible(
flex: 1,
child: Container(
color: Colors.yellow,
child: Center(
child: Text(
'Flexible 2',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
),
),
),
Output the above code will look like this -
In this example, we create a Column widget with three children. The first child is an Expanded widget with a flex value of 2. This means that it will take up twice as much vertical space as each of the Flexible widgets below it. The second and third children are Flexible widgets with a flex value of 1. This means that they will each take up an equal amount of the remaining vertical space after the Expanded widget has been allocated its share.
Each child is a Container widget with a different color and text. The Center widget is used to center the text vertically and horizontally inside each Container.
I hope this example helps you understand how to use the Expanded and Flexible widgets in Flutter to create flexible layouts!
GridView Widget:
The GridView widget is used to create grid layouts. You can use it to display a collection of widgets in a grid format. Here's a complete example of using the GridView widget in Flutter to create a grid of images:
GridView.builder(
itemCount: images.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 4.0,
mainAxisSpacing: 4.0,
),
itemBuilder: (BuildContext context, int index) {
return Image.asset(
images[index],
fit: BoxFit.cover,
);
},
),
The Output of the above code will be in grid view as shown below -
In this example, we create a GridView widget with a SliverGridDelegateWithFixedCrossAxisCount grid delegate, which creates a grid with a fixed number of columns (in this case, 3) and a fixed spacing between the columns and rows. We also specify the number of items in the grid using the itemCount property.
The itemBuilder callback function is called for each item in the grid, and returns a Widget to display at that position. In this case, we use the Image.network widget to display an image loaded from a URL specified in the images list.
I hope this example helps you understand how to use the GridView widget in Flutter to create a grid layout!
Wrap Widget:
The Wrap widget is used to create layouts with wrapped widgets. It allows you to wrap widgets to multiple lines and handles overflow automatically. Here's an example of a wrap widget with buttons:
Wrap(
spacing: 8.0,
runSpacing: 8.0,
children: images.map((image) {
return Container(
width: 100.0,
height: 100.0,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(image),
fit: BoxFit.cover,
),
),
);
}).toList(),
)
Output of the above code will give the following output -
In this example, we create a Wrap widget with a list of images specified in the images list. We specify the spacing and run spacing between the images using the spacing and runSpacing properties, respectively.
We then use the map method to create a new list of Container widgets based on the images list, and use the toList method to convert the resulting Iterable back into a list.
Each Container widget is created with a fixed width and height, and a decoration that specifies an image with a fit of BoxFit.cover. The AssetImage constructor is used to load the image from the app's assets directory using the file path specified in the images list.
I hope this example helps you understand how to use the Wrap widget in Flutter to create a layout of images or other widgets that wrap to the next line when they run out of space in the current line!
These are just a few examples of the different layout widgets available in Flutter. By using these widgets in combination, you can create complex and responsive UIs for your Flutter applications.
let's dive into more advanced layout examples in Flutter....
Nested Layouts:
Nested layouts are a common technique used in Flutter to create more complex UIs. They involve placing one layout widget inside another. Here's an example of a nested layout with a container inside a column:
Column(
children: <Widget>[
Container(
height: 200,
color: Colors.blue,
child: Text('Container 1'),
),
Expanded(
child: Container(
color: Colors.grey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Container 2'),
ElevatedButton(
onPressed: () {},
child: Text('Button'),
),
],
),
),
),
],
);
In this example, we have a column widget with two children: a blue container and a grey container. The grey container is an expanded widget that takes up the remaining space in the column. It contains a column widget with two children: a text widget and a button widget.
Custom Layouts:
Sometimes, the built-in layout widgets in Flutter may not be enough to achieve the desired UI. In such cases, you can create custom layout widgets using the CustomMultiChildLayout widget. Here's an example of a custom layout that arranges its children in a circular pattern:
class CircularLayoutDelegate extends MultiChildLayoutDelegate {
@override
void performLayout(Size size) {
final radius = size.width / 2;
final center = Offset(size.width / 2, size.height / 2);
for (int i = 0; i < childCount; i++) {
final childSize = layoutChild(i, BoxConstraints.loose(size));
final childCenter = center.translate(
radius * math.cos(2 * math.pi * i / childCount),
radius * math.sin(2 * math.pi * i / childCount),
);
positionChild(i, Offset(childCenter.dx - childSize.width / 2, childCenter.dy - childSize.height / 2));
}
}
@override
bool shouldRelayout(covariant MultiChildLayoutDelegate oldDelegate) => true;
}
class CircularLayout extends StatelessWidget {
const CircularLayout({required this.children});
final List<Widget> children;
@override
Widget build(BuildContext context) {
return CustomMultiChildLayout(
delegate: CircularLayoutDelegate(),
children: children.asMap().entries.map((entry) {
return LayoutId(
id: entry.key,
child: entry.value,
);
}).toList(),
);
}
}
In this example, we have a custom layout delegate called CircularLayoutDelegate that arranges its children in a circular pattern. We also have a CircularLayout widget that uses this custom delegate to arrange its children.
Responsive Layouts:
In Flutter, you can create responsive layouts that adapt to different screen sizes using the MediaQuery and LayoutBuilder widgets. Here's an example of a responsive layout with two columns that collapses to a single column on smaller screens:
class ResponsiveLayout extends StatelessWidget {
const ResponsiveLayout({required this.children});
final List<Widget> children;
@override
Widget build(BuildContext context) {
final isSmallScreen = MediaQuery.of(context).size.width < 600;
if (isSmallScreen) {
return Column(
children: children,
);
} else {
return Row(
children: <Widget>[
Expanded(
child: Column(
children: children.sublist(0, children.length ~/ 2),
),
),
Expanded(
child: Column(
children: children.sublist(children.length ~/ 2),
),
),
],
);
}
}
}
In this example, we use the `MediaQuery` widget to determine if the screen size is small or not. If it's small, we display the children in a column. Otherwise, we display the children in two columns using the `Row` and `Expanded` widgets.
Advanced Animation Layouts:
Flutter makes it easy to create advanced animation layouts using the `AnimatedBuilder` and `AnimationController` widgets. Here's an example of an advanced animation layout that animates the position and opacity of its children:
class AnimationLayout extends StatefulWidget {
const AnimationLayout({required this.children});
final List<Widget> children;
@override
_AnimationLayoutState createState() => _AnimationLayoutState();
}
class _AnimationLayoutState extends State<AnimationLayout> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _positionAnimation;
late Animation<double> _opacityAnimation;
@overridevoid initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 2),
);
_positionAnimation = Tween<double>(begin: -100, end: 0).animate(_controller);
_opacityAnimation = Tween<double>(begin: 0, end: 1).animate(_controller);
_controller.forward();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Column(
children: widget.children.asMap().entries.map((entry) {
return Transform.translate(
offset: Offset(0, _positionAnimation.value + 50 * entry.key),
child: Opacity(
opacity: _opacityAnimation.value,
child: entry.value,
),
);
}).toList(),
);
},
);
}
@overridevoid dispose() {
_controller.dispose();
super.dispose();
}
}
In this example, we use the AnimatedBuilder widget to animate the position and opacity of each child in the column. We use a Tween to define the animation range for each property and the AnimationController to control the animation. We also use the Transform.translate widget to animate the position of each child and the Opacity widget to animate the opacity.
I hope these advanced layout examples in Flutter have been helpful! Let me know if you have any further questions.
Example of Advanced Layouts -
This code defines a custom widget called CustomCard that displays a card with an image, title, and description. The CustomCard widget is then used inside a ListView widget to display a list of cards. The layout is responsive and adapts to different screen sizes.
In this example, the CustomCard widget is a custom widget that takes three parameters: imageAsset (the path to the image asset), title (the title of the card), and description (the description of the card). The CustomCard widget is used inside a ListView widget to display a list of cards. The layout of the CustomCard widget is responsive and adapts to different screen sizes. The card has a margin of 10, a border radius of 10, and a box shadow to give it a 3D effect. The image is set to have a height of 200 and to fit the available space. The title and description are displayed using a Text widget with a font size of 20 and 16, respectively. The Column and Row widgets are used to arrange the elements inside the card.
class CustomCard extends StatelessWidget {
final String imageAsset;
final String title;
final String description;
CustomCard({required this.imageAsset, required this.title,required this.description});
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: Offset(0, 3),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Image.asset(
imageAsset,
fit: BoxFit.cover,
height: 200,
),
Container(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 10),
Text(
description,
style: TextStyle(
fontSize: 16,
),
),
],
),
),
],
),
);
The code output will look like this (as shown below) -
In this article, we've covered how to create a wrap, row and col, grid, custom, nested, and responsive layout in Flutter. We defined a `CustomCard` widget that displays a card with an image, title, and description. The `CustomCard` widget was then used inside a `ListView` widget to display a list of cards. The layout was designed to be responsive and adapts to different screen sizes. By using the techniques and widgets outlined in this article, you can create complex and beautiful user interfaces in Flutter. Whether you're building a simple app or a more complex one, understanding how to create custom, nested, and responsive layouts is a key skill for any Flutter developer.
Thanks for reading, and happy coding!
Featured Image: Moyens.net
Mastering Flutter Development Series Article - 7 -> Simplifying Flutter Development: Exploring Gestures and State Management for Seamless App Development