@@ -184,6 +184,7 @@ extension WidgetsExt on Widget {
184184 @_wrapperConstraint ConstraintId ? centerVerticalTo,
185185 OnLayoutCallback ? callback,
186186 double chainWeight = 1 ,
187+ bool percentageTranslate = false ,
187188 }) {
188189 return Constrained (
189190 key: key,
@@ -224,6 +225,7 @@ extension WidgetsExt on Widget {
224225 centerVerticalTo: centerVerticalTo,
225226 callback: callback,
226227 chainWeight: chainWeight,
228+ percentageTranslate: percentageTranslate,
227229 ),
228230 child: this ,
229231 );
@@ -262,7 +264,14 @@ bool _debugEnsureNotEmptyString(String name, String? value) {
262264
263265bool _debugEnsurePercent (String name, double ? percent) {
264266 if (percent == null || percent < 0 || percent > 1 ) {
265- throw ConstraintLayoutException ('$name is between [0-1].' );
267+ throw ConstraintLayoutException ('$name is between [0,1].' );
268+ }
269+ return true ;
270+ }
271+
272+ bool _debugEnsureNegativePercent (String name, double ? percent) {
273+ if (percent == null || percent < - 1 || percent > 1 ) {
274+ throw ConstraintLayoutException ('$name is between [-1,1].' );
266275 }
267276 return true ;
268277}
@@ -455,6 +464,7 @@ class Constraint {
455464
456465 final OnLayoutCallback ? callback;
457466 final double chainWeight;
467+ final bool percentageTranslate;
458468
459469 Constraint ({
460470 this .id,
@@ -493,6 +503,7 @@ class Constraint {
493503 @_wrapperConstraint this .centerVerticalTo,
494504 this .callback,
495505 this .chainWeight = 1 ,
506+ this .percentageTranslate = false ,
496507 });
497508
498509 @override
@@ -534,7 +545,8 @@ class Constraint {
534545 bottomRightTo == other.bottomRightTo &&
535546 centerHorizontalTo == other.centerHorizontalTo &&
536547 centerVerticalTo == other.centerVerticalTo &&
537- callback == other.callback;
548+ callback == other.callback &&
549+ percentageTranslate == other.percentageTranslate;
538550
539551 @override
540552 int get hashCode =>
@@ -572,7 +584,8 @@ class Constraint {
572584 bottomRightTo.hashCode ^
573585 centerHorizontalTo.hashCode ^
574586 centerVerticalTo.hashCode ^
575- callback.hashCode;
587+ callback.hashCode ^
588+ percentageTranslate.hashCode;
576589
577590 bool checkSize (double size) {
578591 if (size == matchParent || size == wrapContent || size == matchConstraint) {
@@ -605,20 +618,26 @@ class Constraint {
605618 assert (_debugEnsurePercent ('heightPercent' , heightPercent));
606619 assert (_debugEnsurePercent ('horizontalBias' , horizontalBias));
607620 assert (_debugEnsurePercent ('verticalBias' , verticalBias));
608- assert (! percentageMargin || _debugEnsurePercent ('leftMargin' , margin.left));
609- assert (! percentageMargin || _debugEnsurePercent ('topMargin' , margin.top));
610- assert (
611- ! percentageMargin || _debugEnsurePercent ('rightMargin' , margin.right));
612621 assert (! percentageMargin ||
613- _debugEnsurePercent ('bottomMargin' , margin.bottom));
622+ _debugEnsureNegativePercent ('leftMargin' , margin.left));
623+ assert (! percentageMargin ||
624+ _debugEnsureNegativePercent ('topMargin' , margin.top));
625+ assert (! percentageMargin ||
626+ _debugEnsureNegativePercent ('rightMargin' , margin.right));
627+ assert (! percentageMargin ||
628+ _debugEnsureNegativePercent ('bottomMargin' , margin.bottom));
614629 assert (! percentageMargin ||
615- _debugEnsurePercent ('leftGoneMargin' , goneMargin.left));
630+ _debugEnsureNegativePercent ('leftGoneMargin' , goneMargin.left));
616631 assert (! percentageMargin ||
617- _debugEnsurePercent ('topGoneMargin' , goneMargin.top));
632+ _debugEnsureNegativePercent ('topGoneMargin' , goneMargin.top));
618633 assert (! percentageMargin ||
619- _debugEnsurePercent ('rightGoneMargin' , goneMargin.right));
634+ _debugEnsureNegativePercent ('rightGoneMargin' , goneMargin.right));
620635 assert (! percentageMargin ||
621- _debugEnsurePercent ('bottomGoneMargin' , goneMargin.bottom));
636+ _debugEnsureNegativePercent ('bottomGoneMargin' , goneMargin.bottom));
637+ assert (! percentageTranslate ||
638+ _debugEnsureNegativePercent ('xTranslate' , translate.dx));
639+ assert (! percentageTranslate ||
640+ _debugEnsureNegativePercent ('yTranslate' , translate.dy));
622641 return true ;
623642 }
624643
@@ -849,6 +868,11 @@ class Constraint {
849868
850869 parentData.callback = callback;
851870
871+ if (parentData.percentageTranslate != percentageTranslate) {
872+ parentData.percentageTranslate = percentageTranslate;
873+ needsPaint = true ;
874+ }
875+
852876 if (needsLayout) {
853877 AbstractNode ? targetParent = renderObject.parent;
854878 if (targetParent is RenderObject ) {
@@ -904,6 +928,7 @@ class _ConstraintBoxData extends ContainerBoxParentData<RenderBox> {
904928 double ? horizontalBias;
905929 double ? verticalBias;
906930 OnLayoutCallback ? callback;
931+ bool ? percentageTranslate;
907932
908933 // for internal use
909934 late Map <ConstraintId , _ConstrainedNode > _tempConstrainedNodes;
@@ -2028,7 +2053,15 @@ class _ConstrainedNode {
20282053 }
20292054 }
20302055
2031- Offset get translate => parentData.translate! ;
2056+ Offset get translate {
2057+ if (! percentageTranslate) {
2058+ return parentData.translate! ;
2059+ } else {
2060+ double dx = renderBox! .size.width * parentData.translate! .dx;
2061+ double dy = renderBox! .size.height * parentData.translate! .dy;
2062+ return Offset (dx, dy);
2063+ }
2064+ }
20322065
20332066 bool get translateConstraint => parentData.translateConstraint! ;
20342067
@@ -2064,6 +2097,8 @@ class _ConstrainedNode {
20642097
20652098 BarrierDirection ? get direction => parentData._direction;
20662099
2100+ bool get percentageTranslate => parentData.percentageTranslate! ;
2101+
20672102 set offset (Offset value) {
20682103 parentData.offset = value;
20692104 }
@@ -2286,6 +2321,7 @@ class _InternalBox extends RenderBox {
22862321 constraintBoxData.callback = null ;
22872322 constraintBoxData._direction = null ;
22882323 constraintBoxData._referencedIds = null ;
2324+ constraintBoxData.percentageTranslate = false ;
22892325 }
22902326}
22912327
0 commit comments