diff --git a/lib/const.dart b/lib/const.dart index 6e7c99e..9da7af2 100644 --- a/lib/const.dart +++ b/lib/const.dart @@ -113,4 +113,5 @@ class Sizes { static const inputWidth = 160.0; static const rowPadding = 10.0; static const doubleRowPadding = rowPadding*2; + static const minViewColumnWidth = 350; } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 03c4af3..f062ef6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -25,6 +25,7 @@ import 'package:in_app_purchase/in_app_purchase.dart'; import 'plugins/circular_slider/single_circular_slider.dart'; import 'package:share/receive_share_state.dart'; import 'package:share/share.dart'; +import 'plugins/DynamicMultiColumnLayout.dart'; import 'utils/logger.dart'; diff --git a/lib/plugins/DynamicMultiColumnLayout.dart b/lib/plugins/DynamicMultiColumnLayout.dart new file mode 100644 index 0000000..116462f --- /dev/null +++ b/lib/plugins/DynamicMultiColumnLayout.dart @@ -0,0 +1,146 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'dart:math' as math; + +class DynamicMultiColumnLayout extends MultiChildRenderObjectWidget { + + final int minColumnWidth; + + DynamicMultiColumnLayout({ + Key key, + this.minColumnWidth: 350, + List children = const [], + }) : super(key: key, children: children); + + @override + RenderCustomLayoutBox createRenderObject(BuildContext context) { + return RenderCustomLayoutBox(minColumnWidth: this.minColumnWidth); + } + +} + +class RenderCustomLayoutBox extends RenderBox + with ContainerRenderObjectMixin, + RenderBoxContainerDefaultsMixin { + + final int minColumnWidth; + + RenderCustomLayoutBox({ + this.minColumnWidth, + List children, + }) { + addAll(children); + } + + @override + void setupParentData(RenderBox child) { + if (child.parentData is! CustomLayoutParentData) { + child.parentData = CustomLayoutParentData(); + } + } + + double _getIntrinsicHeight(double childSize(RenderBox child)) { + double inflexibleSpace = 0.0; + RenderBox child = firstChild; + while (child != null) { + inflexibleSpace += childSize(child); + final FlexParentData childParentData = child.parentData; + child = childParentData.nextSibling; + } + return inflexibleSpace; + } + + double _getIntrinsicWidth(double childSize(RenderBox child)) { + double maxSpace = 0.0; + RenderBox child = firstChild; + while (child != null) { + maxSpace = math.max(maxSpace, childSize(child)); + final FlexParentData childParentData = child.parentData; + child = childParentData.nextSibling; + } + return maxSpace; + } + + @override + double computeMinIntrinsicWidth(double height) { + return _getIntrinsicWidth((RenderBox child) => child.getMinIntrinsicWidth(height)); + } + + @override + double computeMaxIntrinsicWidth(double height) { + return _getIntrinsicWidth((RenderBox child) => child.getMaxIntrinsicWidth(height)); + } + + @override + double computeMinIntrinsicHeight(double width) { + return _getIntrinsicHeight((RenderBox child) => child.getMinIntrinsicHeight(width)); + } + + @override + double computeMaxIntrinsicHeight(double width) { + return _getIntrinsicHeight((RenderBox child) => child.getMaxIntrinsicHeight(width)); + } + + @override + void performLayout() { + int columnsCount; + List columnXPositions = []; + List columnYPositions = []; + if (childCount == 0) { + size = constraints.biggest; + assert(size.isFinite); + return; + } + + columnsCount = (constraints.maxWidth ~/ this.minColumnWidth); + double columnWidth = constraints.maxWidth / columnsCount; + double startY = 0; + for (int i =0; i < columnsCount; i++) { + columnXPositions.add(i*columnWidth); + columnYPositions.add(startY); + } + RenderBox child = firstChild; + while (child != null) { + final CustomLayoutParentData childParentData = child.parentData; + + int columnToAdd = 0; + double minYPosition = columnYPositions[0]; + for (int i=0; i height) { + height = columnYPositions[i]; + } + } + + size = Size(width, height); + } + + @override + void paint(PaintingContext context, Offset offset) { + defaultPaint(context, offset); + } + + @override + bool hitTestChildren(HitTestResult result, { Offset position }) { + return defaultHitTestChildren(result, position: position); + } +} + +class CustomLayoutParentData extends ContainerBoxParentData { + +} \ No newline at end of file diff --git a/lib/view.dart b/lib/view.dart index e6e2d06..b3eef0b 100644 --- a/lib/view.dart +++ b/lib/view.dart @@ -32,9 +32,29 @@ class ViewWidgetState extends State { ); } else { return ListView( - padding: EdgeInsets.all(0.0), - //physics: const AlwaysScrollableScrollPhysics(), - children: _buildChildren(context), + shrinkWrap: true, + padding: EdgeInsets.all(0), + children: [ + DynamicMultiColumnLayout( + minColumnWidth: Sizes.minViewColumnWidth, + children: _buildChildren(context), + ) + ] + ); + return ListView( + shrinkWrap: true, + padding: EdgeInsets.all(0), + children: [ + ConstrainedBox( + constraints: BoxConstraints(maxHeight: 3000), + child: CustomMultiChildLayout( + delegate: ViewLayoutBuilder( + cardsCount: widget.view.cards.length + ), + children: _buildChildren(context), + ), + ) + ], ); } } @@ -49,34 +69,27 @@ class ViewWidgetState extends State { List _buildChildren(BuildContext context) { List result = []; + int layoutChildId = 0; - if (widget.view.badges.isNotEmpty) { - result.insert(0, - Wrap( - alignment: WrapAlignment.center, - spacing: 10.0, - runSpacing: 1.0, - children: _buildBadges(context), + /*if (widget.view.badges.isNotEmpty) { + result.add( + LayoutId( + id: "badges", + child: Wrap( + alignment: WrapAlignment.center, + spacing: 10.0, + runSpacing: 1.0, + children: _buildBadges(context), + ), ) ); - } - - List cards = []; + }*/ widget.view.cards.forEach((HACard card){ - cards.add( - ConstrainedBox( - constraints: BoxConstraints(maxWidth: 500), - child: card.build(context), - ) + result.add( + card.build(context) ); }); - result.add( - Column ( - children: cards, - ) - ); - return result; } @@ -84,7 +97,9 @@ class ViewWidgetState extends State { List result = []; widget.view.badges.forEach((Entity entity) { if (!entity.isHidden) { - result.add(entity.buildBadgeWidget(context)); + result.add( + entity.buildBadgeWidget(context) + ); } }); return result; @@ -95,5 +110,50 @@ class ViewWidgetState extends State { super.dispose(); } +} +class ViewLayoutBuilder extends MultiChildLayoutDelegate { + final int cardsCount; + + ViewLayoutBuilder({@required this.cardsCount}); + + @override + void performLayout(Size size) { + int columnsCount = (size.width ~/ Sizes.minViewColumnWidth); + double columnWidth = size.width / columnsCount; + List columnXPositions = []; + List columnYPositions = []; + double startY = 0; + if (hasChild("badges")) { + Size badgesSizes = layoutChild( + 'badges', BoxConstraints.tightFor(width: size.width)); + startY += badgesSizes.height; + positionChild('badges', Offset(0, 0)); + } + for (int i =0; i < columnsCount; i++) { + columnXPositions.add(i*columnWidth); + columnYPositions.add(startY); + } + for (int i = 0; i < cardsCount; i++) { + final String cardId = 'card_$i'; + + if (hasChild(cardId)) { + int columnToAdd = 0; + double minYPosition = columnYPositions[0]; + for (int i=1; i false; } \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index ce6d395..9d96ec2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -164,7 +164,7 @@ packages: name: flutter_webview_plugin url: "https://pub.dartlang.org" source: hosted - version: "0.3.7" + version: "0.3.8" http: dependency: transitive description: @@ -374,7 +374,7 @@ packages: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "5.1.2" + version: "5.1.3" uuid: dependency: transitive description: