Last active
July 16, 2019 12:06
-
-
Save szotp/f3fafddacfa6d32a8e127d77cc4678fe to your computer and use it in GitHub Desktop.
OverflowFallback
This file contains 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'; | |
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