@@ -185,6 +185,7 @@ extension ConstrainedWidgetsExt on Widget {
185
185
double minHeight = 0 ,
186
186
double maxHeight = matchParent,
187
187
double ? widthHeightRatio,
188
+ bool ? ratioBaseOnWidth,
188
189
}) {
189
190
return Constrained (
190
191
key: key,
@@ -231,6 +232,7 @@ extension ConstrainedWidgetsExt on Widget {
231
232
minHeight: minHeight,
232
233
maxHeight: maxHeight,
233
234
widthHeightRatio: widthHeightRatio,
235
+ ratioBaseOnWidth: ratioBaseOnWidth,
234
236
),
235
237
child: this ,
236
238
);
@@ -526,6 +528,12 @@ class Constraint {
526
528
/// inferred (fixed size, matchParent, matchConstraint with two constraints)
527
529
final double ? widthHeightRatio;
528
530
531
+ /// By default, ConstraintLayout will automatically decide which side to base on and
532
+ /// calculate the size of the other side based on widthHeightRatio. But if both sides
533
+ /// are matchConstraint, it cannot be determined automatically. At this point, you need
534
+ /// to specify the ratioBaseOnWidth parameter. The default value of null means automatically decide
535
+ final bool ? ratioBaseOnWidth;
536
+
529
537
Constraint ({
530
538
this .id,
531
539
this .width = wrapContent,
@@ -569,6 +577,7 @@ class Constraint {
569
577
this .minHeight = 0 ,
570
578
this .maxHeight = matchParent,
571
579
this .widthHeightRatio,
580
+ this .ratioBaseOnWidth,
572
581
});
573
582
574
583
@override
@@ -616,7 +625,8 @@ class Constraint {
616
625
maxWidth == other.maxWidth &&
617
626
minHeight == other.minHeight &&
618
627
maxHeight == other.maxHeight &&
619
- widthHeightRatio == other.widthHeightRatio;
628
+ widthHeightRatio == other.widthHeightRatio &&
629
+ ratioBaseOnWidth == other.ratioBaseOnWidth;
620
630
621
631
@override
622
632
int get hashCode =>
@@ -660,7 +670,8 @@ class Constraint {
660
670
maxWidth.hashCode ^
661
671
minHeight.hashCode ^
662
672
maxHeight.hashCode ^
663
- widthHeightRatio.hashCode;
673
+ widthHeightRatio.hashCode ^
674
+ ratioBaseOnWidth.hashCode;
664
675
665
676
bool checkSize (double size) {
666
677
if (size == matchParent || size == wrapContent || size == matchConstraint) {
@@ -1009,6 +1020,11 @@ class Constraint {
1009
1020
needsLayout = true ;
1010
1021
}
1011
1022
1023
+ if (parentData.ratioBaseOnWidth != ratioBaseOnWidth) {
1024
+ parentData.ratioBaseOnWidth = ratioBaseOnWidth;
1025
+ needsLayout = true ;
1026
+ }
1027
+
1012
1028
if (needsLayout) {
1013
1029
AbstractNode ? targetParent = renderObject.parent;
1014
1030
if (needsRecalculateConstraints) {
@@ -1075,6 +1091,7 @@ class _ConstraintBoxData extends ContainerBoxParentData<RenderBox> {
1075
1091
double ? minHeight;
1076
1092
double ? maxHeight;
1077
1093
double ? widthHeightRatio;
1094
+ bool ? ratioBaseOnWidth;
1078
1095
1079
1096
// for internal use
1080
1097
late Map <ConstraintId , _ConstrainedNode > _constrainedNodeMap;
@@ -1412,8 +1429,13 @@ class _ConstraintRenderBox extends RenderBox
1412
1429
1413
1430
if (element.widthHeightRatio != null ) {
1414
1431
if (element.widthIsExact && element.heightIsExact) {
1415
- throw ConstraintLayoutException (
1416
- 'When setting widthHeightRatio for ${element .nodeId }, full constraints cannot be set on both sides at the same time.' );
1432
+ if (element.width == matchConstraint &&
1433
+ element.height == matchConstraint) {
1434
+ if (element.ratioBaseOnWidth == null ) {
1435
+ throw ConstraintLayoutException (
1436
+ 'When setting widthHeightRatio for ${element .nodeId }, ratioBaseOnWidth is required.' );
1437
+ }
1438
+ }
1417
1439
} else if (! element.widthIsExact && ! element.heightIsExact) {
1418
1440
throw ConstraintLayoutException (
1419
1441
'When setting widthHeightRatio for ${element .nodeId }, one side needs full constraints.' );
@@ -1715,7 +1737,9 @@ class _ConstraintRenderBox extends RenderBox
1715
1737
}());
1716
1738
maxWidth = minWidth;
1717
1739
} else if (width == matchConstraint) {
1718
- if (element.widthHeightRatio != null && ! element.widthIsExact) {
1740
+ if (element.widthHeightRatio != null &&
1741
+ element.heightIsExact &&
1742
+ element.ratioBaseOnWidth != true ) {
1719
1743
/// The width needs to be calculated later based on the height
1720
1744
element.widthBasedHeight = true ;
1721
1745
minWidth = 0 ;
@@ -1797,7 +1821,9 @@ class _ConstraintRenderBox extends RenderBox
1797
1821
}());
1798
1822
maxHeight = minHeight;
1799
1823
} else if (height == matchConstraint) {
1800
- if (element.widthHeightRatio != null && element.widthIsExact) {
1824
+ if (element.widthHeightRatio != null &&
1825
+ element.widthIsExact &&
1826
+ element.ratioBaseOnWidth != false ) {
1801
1827
/// The height needs to be calculated later based on the width
1802
1828
/// minWidth == maxWidth
1803
1829
minHeight = minWidth / element.widthHeightRatio! ;
@@ -2471,6 +2497,8 @@ class _ConstrainedNode {
2471
2497
2472
2498
double ? get widthHeightRatio => parentData.widthHeightRatio;
2473
2499
2500
+ bool ? get ratioBaseOnWidth => parentData.ratioBaseOnWidth;
2501
+
2474
2502
/// fixed size, matchParent, matchConstraint with two constraints
2475
2503
bool get widthIsExact =>
2476
2504
width >= 0 ||
@@ -2707,6 +2735,7 @@ class _InternalBox extends RenderBox {
2707
2735
constraintBoxData.minHeight = 0 ;
2708
2736
constraintBoxData.maxHeight = matchParent;
2709
2737
constraintBoxData.widthHeightRatio = null ;
2738
+ constraintBoxData.ratioBaseOnWidth = null ;
2710
2739
}
2711
2740
}
2712
2741
0 commit comments