Skip to content

Instantly share code, notes, and snippets.

@harkairt
Last active March 8, 2023 15:17
Show Gist options
  • Save harkairt/fd9fbe6096fd136ab808827b55842bdc to your computer and use it in GitHub Desktop.
Save harkairt/fd9fbe6096fd136ab808827b55842bdc to your computer and use it in GitHub Desktop.
Fill vertical viewport, but scrollable unsufficient height
import 'package:flutter/material.dart';
const mainText = "AAAAAAAAAAAAAAAAAAAAAAAAAAA";
const subText = "BBBBBBBBBBBBBBBBBBBBBBBBBBB";
final greenBorder = BoxDecoration(border: Border.all(color: Colors.green));
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: DefaultTextStyle(
style: const TextStyle(fontSize: 40, color: Colors.black),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: const [
Expanded(child: ConstrainedHeightTextSliverFillRemaining()),
Expanded(child: UnconstrainedHeightTextSliverFillRemaining()),
Expanded(child: UnconstrainedHeightText()),
Expanded(child: ConstrainedHeightText()),
],
),
),
),
);
}
}
class ConstrainedHeightText extends StatelessWidget {
const ConstrainedHeightText({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ScrollableColumn(
children: [
const Header('ScrollableColumn with a constrained height'),
Container(
decoration: greenBorder,
child: const SizedBox(
width: 200,
height: 260,
child: Text(mainText),
),
),
Container(
decoration: greenBorder,
child: const SizedBox(
width: 200,
height: 260,
child: Text(subText),
),
),
const Spacer(),
const Footer(),
],
);
}
}
class UnconstrainedHeightText extends StatelessWidget {
const UnconstrainedHeightText({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ScrollableColumn(
children: [
const Header('ScrollableColumn without height constraints'),
Container(
decoration: greenBorder,
child: const SizedBox(
width: 200,
child: Text(mainText),
),
),
Container(
decoration: greenBorder,
child: const SizedBox(
width: 200,
child: Text(subText),
),
),
const Spacer(),
const Footer(),
],
);
}
}
class ConstrainedHeightTextSliverFillRemaining extends StatelessWidget {
const ConstrainedHeightTextSliverFillRemaining({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
SliverFillRemaining(
child: Column(
children: [
const Header('SliverFillRemaining with a constrained height'),
Container(
decoration: greenBorder,
child: const SizedBox(
width: 200,
height: 260,
child: Text(mainText),
),
),
Container(
decoration: greenBorder,
child: const SizedBox(
width: 200,
height: 260,
child: Text(subText),
),
),
const Spacer(),
const Footer(),
],
),
)
],
);
}
}
class UnconstrainedHeightTextSliverFillRemaining extends StatelessWidget {
const UnconstrainedHeightTextSliverFillRemaining({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
SliverFillRemaining(
child: Column(
children: [
const Header('SliverFillRemaining without height constraints'),
Container(
decoration: greenBorder,
child: const SizedBox(
width: 200,
child: Text(mainText),
),
),
Container(
decoration: greenBorder,
child: const SizedBox(
width: 200,
child: Text(subText),
),
),
const Spacer(),
const Footer(),
],
),
)
],
);
}
}
class Header extends StatelessWidget {
const Header(this.title, {Key? key}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) => Padding(
padding: const EdgeInsets.all(16),
child: Text(
title,
style: const TextStyle(fontSize: 18, color: Colors.black),
textAlign: TextAlign.center,
),
);
}
class Footer extends StatelessWidget {
const Footer({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => const Text('Footer');
}
// A little modified (added padding) version of
// https://github.com/flutter/flutter/issues/18711#issuecomment-810701866
class ScrollableColumn extends StatelessWidget {
const ScrollableColumn(
{Key? key,
required this.children,
this.crossAxisAlignment = CrossAxisAlignment.center,
this.textDirection,
this.mainAxisAlignment = MainAxisAlignment.start,
this.mainAxisSize = MainAxisSize.max,
this.verticalDirection = VerticalDirection.down,
this.textBaseline,
this.padding,
this.controller})
: super(key: key);
final List<Widget> children;
final CrossAxisAlignment crossAxisAlignment;
final TextDirection? textDirection;
final MainAxisAlignment mainAxisAlignment;
final MainAxisSize mainAxisSize;
final VerticalDirection verticalDirection;
final TextBaseline? textBaseline;
final EdgeInsets? padding;
final ScrollController? controller;
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (_, constraints) {
return SingleChildScrollView(
padding: padding,
controller: controller,
child: Builder(
builder: (context) {
return ConstrainedBox(
// Constrained box stops the column from getting too small, forcing it to be at least as tall as it's parent
constraints: BoxConstraints(
minWidth: constraints.maxWidth,
minHeight: constraints.maxHeight - (padding?.vertical ?? 0),
),
// Intrinsic height stops the column from expanding forever when it's height becomes unbounded
// It will always use the full height of the parent, or the natural size of the children, whichever is greater.
child: IntrinsicHeight(
child: Column(
crossAxisAlignment: crossAxisAlignment,
textDirection: textDirection,
mainAxisAlignment: mainAxisAlignment,
mainAxisSize: mainAxisSize,
verticalDirection: verticalDirection,
textBaseline: textBaseline,
children: children,
),
),
);
},
),
);
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment