Last active
May 27, 2021 16:21
-
-
Save pingbird/f323bdba402b4360eb7ddef340c5753b to your computer and use it in GitHub Desktop.
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
| class MyHomePage extends StatelessWidget { | |
| Widget buildCard(BuildContext context, bool topEdge, bool bottomEdge, Color color) { | |
| final cardBorder = BorderSide(color: color, width: 2); | |
| return Padding( | |
| padding: EdgeInsets.only( | |
| left: 8.0, | |
| right: 8.0, | |
| top: topEdge ? 8.0 : 0.0, | |
| bottom: bottomEdge ? 8.0 : 0.0, | |
| ), | |
| child: DecoratedBox( | |
| decoration: BoxDecoration( | |
| border: Border( | |
| left: cardBorder, | |
| right: cardBorder, | |
| top: topEdge ? cardBorder : BorderSide.none, | |
| bottom: bottomEdge ? cardBorder : BorderSide.none, | |
| ), | |
| ), | |
| ), | |
| ); | |
| } | |
| build(BuildContext context) { | |
| final rand = Random(); | |
| return Scaffold( | |
| body: SingleChildScrollView( | |
| scrollDirection: Axis.horizontal, | |
| child: ColumnWrap( | |
| cardWidth: 200.0, | |
| cards: [ | |
| ColumnWrapCard( | |
| buildCard: (context, topEdge, bottomEdge) => buildCard(context, topEdge, bottomEdge, Colors.red), | |
| children: [ | |
| for (var i = 0; i < 2; i++) | |
| Padding( | |
| padding: const EdgeInsets.all(16.0), | |
| child: Text('$i' * rand.nextInt(200)), | |
| ), | |
| ], | |
| ), | |
| ColumnWrapCard( | |
| buildCard: (context, topEdge, bottomEdge) => buildCard(context, topEdge, bottomEdge, Colors.green), | |
| children: [ | |
| for (var i = 0; i < 5; i++) | |
| Padding( | |
| padding: const EdgeInsets.all(16.0), | |
| child: Text('$i' * rand.nextInt(200)), | |
| ), | |
| ], | |
| ), | |
| ColumnWrapCard( | |
| buildCard: (context, topEdge, bottomEdge) => buildCard(context, topEdge, bottomEdge, Colors.blue), | |
| children: [ | |
| for (var i = 0; i < 2; i++) | |
| Padding( | |
| padding: const EdgeInsets.all(16.0), | |
| child: Text('$i' * rand.nextInt(200)), | |
| ), | |
| ], | |
| ), | |
| ], | |
| ), | |
| ), | |
| ); | |
| } | |
| } | |
| class ColumnWrapCard { | |
| final Widget Function(BuildContext context, bool topEdge, bool bottomEdge) buildCard; | |
| final List<Widget> children; | |
| const ColumnWrapCard({ | |
| required this.buildCard, | |
| required this.children, | |
| }); | |
| } | |
| class ColumnWrap extends StatelessWidget { | |
| final List<ColumnWrapCard> cards; | |
| final double cardWidth; | |
| const ColumnWrap({ | |
| required this.cards, | |
| required this.cardWidth, | |
| }); | |
| @override | |
| Widget build(BuildContext context) { | |
| return CustomBoxy( | |
| delegate: ColumnWrappingBoxy( | |
| cards: cards, | |
| cardWidth: cardWidth, | |
| ), | |
| children: [ | |
| for (final card in cards) | |
| ...card.children, | |
| ], | |
| ); | |
| } | |
| } | |
| class ColumnWrappingBoxy extends BoxyDelegate { | |
| final List<ColumnWrapCard> cards; | |
| final double cardWidth; | |
| ColumnWrappingBoxy({ | |
| required this.cards, | |
| required this.cardWidth, | |
| }); | |
| @override | |
| Size layout() { | |
| final height = constraints.maxHeight; | |
| final childConstraints = BoxConstraints.tightFor(width: cardWidth); | |
| var col = 0; | |
| var endCol = 0; | |
| var y = 0.0; | |
| var childIndex = 0; | |
| for (final card in cards) { | |
| var topEdge = true; | |
| var topY = y; | |
| void wrap([bool bottomEdge = true]) { | |
| inflate( | |
| card.buildCard(buildContext, topEdge, bottomEdge), | |
| ).layoutRect( | |
| Offset(col * cardWidth, topY) | |
| & Size(cardWidth, (bottomEdge ? y : height) - topY), | |
| ); | |
| } | |
| for (var i = 0; i < card.children.length; i++) { | |
| // Lay out child | |
| final child = getChild(childIndex++); | |
| final childSize = child.layout(childConstraints); | |
| if (y + childSize.height > height) { | |
| // Wrap card to new column | |
| wrap(false); | |
| y = 0.0; | |
| topY = 0.0; | |
| topEdge = false; | |
| col++; | |
| } | |
| child.position(Offset(col * cardWidth, y)); | |
| y += childSize.height; | |
| endCol = col; | |
| if (i == card.children.length - 1) { | |
| // Last item, build card | |
| wrap(); | |
| } | |
| } | |
| } | |
| return Size(endCol * cardWidth, height); | |
| } | |
| @override | |
| void paintChildren() { | |
| for (final child in children.reversed) child.paint(); | |
| } | |
| @override | |
| bool hitTest(Offset position) { | |
| for (final child in children) { | |
| if (child.hitTest()) { | |
| addHit(); | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| @override | |
| bool shouldRelayout(ColumnWrappingBoxy oldDelegate) { | |
| return true; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment