Skip to content

Instantly share code, notes, and snippets.

@szotp
Last active July 16, 2019 12:06
Show Gist options
  • Save szotp/f3fafddacfa6d32a8e127d77cc4678fe to your computer and use it in GitHub Desktop.
Save szotp/f3fafddacfa6d32a8e127d77cc4678fe to your computer and use it in GitHub Desktop.
OverflowFallback
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
typedef OverflowCallback = void Function(double minimalHeight);
class RenderOverflowFallback extends RenderMetaData {
bool shouldClip = false;
@override
void performLayout() {
super.performLayout();
final minimumPossibleHeight = child?.getMinIntrinsicHeight(size.width) ?? 0;
final overflow = minimumPossibleHeight - size.height;
if (overflow > 0) {
final constraints =
this.constraints.copyWith(maxHeight: minimumPossibleHeight);
this.child.layout(constraints);
OverflowCallback callback = metaData;
callback?.call(minimumPossibleHeight);
shouldClip = true;
}
}
@override
void paint(PaintingContext context, Offset offset) {
if (shouldClip) {
final rect = Offset.zero & size;
context.pushClipRect(needsCompositing, offset, rect, super.paint,
clipBehavior: Clip.hardEdge);
} else {
super.paint(context, offset);
}
}
}
class OverflowFallback extends MetaData {
final OverflowCallback onOverflow;
OverflowFallback({this.onOverflow, Widget child})
: super(child: child, metaData: onOverflow);
@override
RenderMetaData createRenderObject(BuildContext context) {
return RenderOverflowFallback()..metaData = metaData;
}
}
class AutoScrollable extends StatefulWidget {
final Widget child;
const AutoScrollable({Key key, this.child}) : super(key: key);
@override
_AutoScrollableState createState() => _AutoScrollableState();
}
class _AutoScrollableState extends State<AutoScrollable> {
KeyedSubtree _child;
double height;
@override
void initState() {
_child = KeyedSubtree(child: widget.child, key: GlobalKey());
super.initState();
}
@override
void reassemble() {
if (height != null) {
setState(() {
// not clear to me in which cases we need reset this
// possibly we need to continously check minimumPossibleHeight
height = null;
});
}
super.reassemble();
}
@override
Widget build(BuildContext context) {
if (height != null) {
return SingleChildScrollView(
child: SizedBox(
height: height,
child: _child,
),
);
} else {
return OverflowFallback(
child: _child,
onOverflow: (height) {
Future.microtask(() {
setState(() {
this.height = height;
});
});
},
);
}
}
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Container(
color: Colors.yellow,
padding: EdgeInsets.all(10),
child: AutoScrollable(
child: Column(
children: <Widget>[
Container(
color: Colors.red,
height: 100,
),
Text('Hello world'),
Container(
color: Colors.blue,
height: 2000,
),
],
),
),
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment