Skip to content

Instantly share code, notes, and snippets.

@craiglabenz
Created July 18, 2025 20:49
Show Gist options
  • Save craiglabenz/70e568b0daca412b306f5e664d196c4e to your computer and use it in GitHub Desktop.
Save craiglabenz/70e568b0daca412b306f5e664d196c4e to your computer and use it in GitHub Desktop.
Single-page scrollable only if too tall, with a sticky footer
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(colorSchemeSeed: Colors.blue),
home: const ExpandingScrollableLayout(),
);
}
}
class ExpandingScrollableLayout extends StatelessWidget {
const ExpandingScrollableLayout({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
// LayoutBuilder provides the parent's constraints, like the screen height.
body: LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return SingleChildScrollView(
child: ConstrainedBox(
// Constrain the child to be at least as tall as the viewport.
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
// IntrinsicHeight ensures the Column fills the height of the ConstrainedBox.
child: IntrinsicHeight(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
// 1. Top cluster of widgets
Container(
padding: const EdgeInsets.all(12.0),
decoration: BoxDecoration(
color: Colors.green.shade100,
border: Border.all(color: Colors.green),
borderRadius: BorderRadius.circular(8.0),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'Column',
style: TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
// Replace these with your actual widgets
Container(height: 50, color: Colors.blue),
const SizedBox(height: 10),
Container(height: 50, color: Colors.blue),
const SizedBox(height: 10),
Container(height: 50, color: Colors.blue),
const SizedBox(height: 10),
Container(height: 50, color: Colors.blue),
const SizedBox(height: 10),
Container(height: 50, color: Colors.blue),
],
),
),
// 2. The expanding spacer
const Spacer(), // This takes up all available vertical space.
// 3. Minimum space + bottom widget
// This inner column ensures the SizedBox and bottom widget are grouped.
Padding(
padding: const EdgeInsets.symmetric(vertical: 24),
child: Text('Sticky Footer widget'),
),
],
),
),
),
),
);
},
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment