Home
Dart
OOP
Flutter
Contact

Building Complex UIs

Master Flutter's layout widgets to create responsive, production-grade interfaces.

Choosing the Right Layout Widget

WidgetDirectionUse When
RowHorizontalArranging items side by side (toolbar, chips)
ColumnVerticalStacking items vertically (form, list)
StackOverlayLayering widgets (badges, overlays)
WrapFlowTags, chips that flow to next line
ListViewScrollableLong lists with lazy rendering
GridViewGridPhoto galleries, product grids
💡 Flexible vs Expanded Flexible lets a child take only the space it needs, while Expanded forces the child to fill all available space. Use Flexible for content that varies in size and Expanded for content that should stretch.

Responsive Design Patterns

Flutter doesn't have CSS media queries, but you can achieve responsive layouts using LayoutBuilder and MediaQuery:

responsive_layout.dart
class ResponsiveLayout extends StatelessWidget {
  final Widget mobile;
  final Widget tablet;
  final Widget desktop;

  const ResponsiveLayout({
    required this.mobile,
    required this.tablet,
    required this.desktop,
  });

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.maxWidth 600) return mobile;
        if (constraints.maxWidth 1200) return tablet;
        return desktop;
      },
    );
  }
}

Row & Column

Row arranges children horizontally; Column arranges vertically. Both use the same alignment properties:

row_column.dart
// Row — horizontal layout
Row(
  mainAxisAlignment: MainAxisAlignment.spaceBetween,
  crossAxisAlignment: CrossAxisAlignment.center,
  children: [
    Icon(Icons.menu),
    Text('dftacademy'),
    Icon(Icons.account_circle),
  ],
)

// Column — vertical layout
Column(
  mainAxisAlignment: MainAxisAlignment.start,
  crossAxisAlignment: CrossAxisAlignment.stretch,
  children: [
    Text('Title', style: Theme.of(context).textTheme.headlineMedium),
    SizedBox(height: 8),
    Text('Subtitle text here'),
    SizedBox(height: 16),
    Divider(),
    Text('Body content...'),
  ],
)

Flex & Expanded

Expanded makes a child fill available space. Flexible allows a child to be smaller:

flex_layout.dart
Row(children: [
  Expanded(
    flex: 2,
    child: Container(color: Colors.blue, height: 100),
  ),
  SizedBox(width: 16),
  Expanded(
    flex: 1,
    child: Container(color: Colors.red, height: 100),
  ),
])

Stack

Stack overlays widgets on top of each other. Use Positioned for precise placement:

stack_layout.dart
Stack(
  clipBehavior: Clip.none,
  children: [
    Container(
      width: 200, height: 200,
      decoration: BoxDecoration(
        color: Colors.indigo,
        borderRadius: BorderRadius.circular(16),
      ),
    ),
    Positioned(
      top: -10, right: -10,
      child: CircleAvatar(backgroundColor: Colors.red,
        child: Text('3')),
    ),
    Positioned(
      bottom: 16, left: 16,
      child: Text('Card Title', style: TextStyle(color: Colors.white)),
    ),
  ],
)

ListView

Scrollable list of widgets. Use ListView.builder for large datasets (lazy rendering):

listview_example.dart
// Static ListView
ListView(children: [
  ListTile(leading: Icon(Icons.inbox), title: Text('Inbox')),
  ListTile(leading: Icon(Icons.send), title: Text('Sent')),
  ListTile(leading: Icon(Icons.drafts), title: Text('Drafts')),
])

// Lazy ListView.builder (recommended for large lists)
ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text(items[index].name),
      subtitle: Text(items[index].description),
      trailing: Icon(Icons.chevron_right),
    );
  },
)

GridView

2D scrollable grid. Perfect for dashboards and media galleries:

gridview_example.dart
GridView.count(
  crossAxisCount: 3,
  mainAxisSpacing: 12,
  crossAxisSpacing: 12,
  padding: const EdgeInsets.all(16),
  children: dashboardItems.map((item) {
    return Card(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(item.icon, size: 32),
          SizedBox(height: 8),
          Text(item.label),
        ],
      ),
    );
  }).toList(),
)

Responsive Design

Use LayoutBuilder and MediaQuery for responsive layouts:

responsive.dart
LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth > 600) {
      // Desktop: side-by-side
      return Row(children: [
        Expanded(child: Sidebar()),
        Expanded(flex: 3, child: Content()),
      ]);
    } else {
      // Mobile: stacked
      return Column(children: [
        Content(),
      ]);
    }
  },
)

Real-World Example: Media Dashboard Grid

dashboard.dart
class MediaDashboard extends StatelessWidget {
  const MediaDashboard({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Media Dashboard')),
      body: LayoutBuilder(
        builder: (context, constraints) {
          var crossCount = constraints.maxWidth > 900 ? 4
              : constraints.maxWidth > 600 ? 3 : 2;

          return GridView.count(
            crossAxisCount: crossCount,
            padding: const EdgeInsets.all(16),
            mainAxisSpacing: 16,
            crossAxisSpacing: 16,
            childAspectRatio: 0.85,
            children: List.generate(12, (index) {
              return Card(
                clipBehavior: Clip.antiAlias,
                child: Column(crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Expanded(child: Container(color: Colors.indigo[100 + index * 50])),
                    Padding(padding: const EdgeInsets.all(12),
                      child: Column(crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text('Video ${index + 1}', style: const TextStyle(fontWeight: FontWeight.bold)),
                          Text('${(index + 1) * 3} min', style: TextStyle(color: Colors.grey[600])),
                        ],
                      ),
                    ),
                  ],
                ),
              );
            }),
          );
        },
      ),
    );
  }
}

Summary

  • Row/Column for directional layouts, Stack for overlays
  • Expanded and Flexible control space distribution
  • ListView.builder for lazy lists, GridView.count for grids
  • LayoutBuilder enables responsive breakpoints
🚀 Next Step Continue to State Management.
K
Kesavaraja Murugesan
Flutter Developer & Educator

Flutter developer with 3 years of experience building production-grade mobile applications. Passionate about teaching clean architecture patterns and helping developers write maintainable, scalable code.

← Widgets Next: State Management →