Created
July 18, 2025 20:49
-
-
Save craiglabenz/70e568b0daca412b306f5e664d196c4e to your computer and use it in GitHub Desktop.
Single-page scrollable only if too tall, with a sticky footer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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