Skip to content

Commit bd50fad

Browse files
author
fbchen
committed
support virtual helper widgets
1 parent fe7115e commit bd50fad

File tree

1 file changed

+180
-56
lines changed

1 file changed

+180
-56
lines changed

lib/src/constraint_layout.dart

Lines changed: 180 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,6 +1465,7 @@ class _ConstraintRenderBox extends RenderBox
14651465

14661466
bool _needsRecalculateConstraints = true;
14671467
bool _needsReorderChildren = true;
1468+
int _buildNodeTreesCount = 0;
14681469
final Map<ConstraintId, _ConstrainedNode> _helperNodeMap = HashMap();
14691470

14701471
/// For layout
@@ -1499,6 +1500,41 @@ class _ConstraintRenderBox extends RenderBox
14991500
}
15001501
if (!isSameList) {
15011502
_childConstraints = value;
1503+
_helperNodeMap.clear();
1504+
for (final element in _childConstraints ?? []) {
1505+
if (element is GuidelineDefine) {
1506+
_ConstraintBoxData constraintBoxData = _ConstraintBoxData();
1507+
_HelperBox.initParentData(constraintBoxData);
1508+
_GuidelineRenderBox.initParentData(
1509+
constraintBoxData,
1510+
id: element.id!,
1511+
horizontal: element.horizontal,
1512+
guidelineBegin: element.guidelineBegin,
1513+
guidelineEnd: element.guidelineEnd,
1514+
guidelinePercent: element.guidelinePercent,
1515+
);
1516+
_ConstrainedNode constrainedNode = _ConstrainedNode()
1517+
..nodeId = element.id!
1518+
..parentData = constraintBoxData
1519+
..index = -1
1520+
..depth = 1;
1521+
_helperNodeMap[element.id!] = constrainedNode;
1522+
} else if (element is BarrierDefine) {
1523+
_ConstraintBoxData constraintBoxData = _ConstraintBoxData();
1524+
_HelperBox.initParentData(constraintBoxData);
1525+
_BarrierRenderBox.initParentData(
1526+
constraintBoxData,
1527+
id: element.id!,
1528+
direction: element.direction,
1529+
referencedIds: element.referencedIds,
1530+
);
1531+
_ConstrainedNode constrainedNode = _ConstrainedNode()
1532+
..nodeId = element.id!
1533+
..parentData = constraintBoxData
1534+
..index = -1;
1535+
_helperNodeMap[element.id!] = constrainedNode;
1536+
}
1537+
}
15021538
markNeedsRecalculateConstraints();
15031539
markNeedsLayout();
15041540
}
@@ -1639,6 +1675,13 @@ class _ConstraintRenderBox extends RenderBox
16391675
child = childParentData.nextSibling;
16401676
}
16411677

1678+
/// All ids referenced by Barrier must be defined
1679+
for (final element in _helperNodeMap.values) {
1680+
if (element.isBarrier) {
1681+
constraintsIdSet.addAll(element.referencedIds!);
1682+
}
1683+
}
1684+
16421685
/// The id used by all constraints must be defined
16431686
Set<ConstraintId> illegalIdSet = constraintsIdSet.difference(idSet);
16441687
Set<RelativeConstraintId> relativeIds =
@@ -1647,18 +1690,6 @@ class _ConstraintRenderBox extends RenderBox
16471690
throw ConstraintLayoutException(
16481691
'These ids ${illegalIdSet.difference(relativeIds)} are not yet defined.');
16491692
}
1650-
1651-
/// All ids referenced by Barrier must be defined
1652-
// for (final element in _helperNodeMap.values) {
1653-
// if (element.isBarrier) {
1654-
// Set<ConstraintId> illegalIdSet =
1655-
// element.referencedIds!.toSet().difference(idSet);
1656-
// if (illegalIdSet.isNotEmpty) {
1657-
// throw ConstraintLayoutException(
1658-
// 'These ids $illegalIdSet are not yet defined.');
1659-
// }
1660-
// }
1661-
// }
16621693
}
16631694

16641695
/// There should be no loop constraints
@@ -1781,26 +1812,59 @@ class _ConstraintRenderBox extends RenderBox
17811812

17821813
Map<ConstraintId, _ConstrainedNode> _buildConstrainedNodeTrees() {
17831814
Map<ConstraintId, _ConstrainedNode> nodesMap = HashMap();
1815+
_buildNodeTreesCount++;
17841816

17851817
_ConstrainedNode _getConstrainedNodeForChild(ConstraintId id) {
17861818
if (id == parent) {
17871819
return _parentNode;
17881820
}
1789-
_ConstrainedNode? node = id.getCacheNode(hashCode);
1821+
1822+
/// Fewer reads to nodesMap for faster constraint building
1823+
_ConstrainedNode? node = id.getCacheNode(_buildNodeTreesCount ^ hashCode);
17901824
if (node != null) {
17911825
return node;
17921826
}
1827+
17931828
node = nodesMap[id];
17941829
if (node == null) {
17951830
node = _ConstrainedNode()..nodeId = id;
17961831
nodesMap[id] = node;
17971832
}
1798-
id.setCacheNode(hashCode, node);
1833+
id.setCacheNode(_buildNodeTreesCount ^ hashCode, node);
17991834
return node;
18001835
}
18011836

18021837
if (_helperNodeMap.isNotEmpty) {
18031838
nodesMap.addAll(_helperNodeMap);
1839+
for (final element in _helperNodeMap.values) {
1840+
if (element.parentData.left != null) {
1841+
element.leftConstraint =
1842+
_getConstrainedNodeForChild(element.parentData.left!.id!);
1843+
element.leftAlignType = element.parentData.left!.type;
1844+
}
1845+
1846+
if (element.parentData.top != null) {
1847+
element.topConstraint =
1848+
_getConstrainedNodeForChild(element.parentData.top!.id!);
1849+
element.topAlignType = element.parentData.top!.type;
1850+
}
1851+
1852+
if (element.parentData.right != null) {
1853+
element.rightConstraint =
1854+
_getConstrainedNodeForChild(element.parentData.right!.id!);
1855+
element.rightAlignType = element.parentData.right!.type;
1856+
}
1857+
1858+
if (element.parentData.bottom != null) {
1859+
element.bottomConstraint =
1860+
_getConstrainedNodeForChild(element.parentData.bottom!.id!);
1861+
element.bottomAlignType = element.parentData.bottom!.type;
1862+
}
1863+
1864+
if (element.isBarrier) {
1865+
element.parentData._constrainedNodeMap = nodesMap;
1866+
}
1867+
}
18041868
}
18051869

18061870
RenderBox? child = firstChild;
@@ -3055,10 +3119,7 @@ class _ConstrainedNode {
30553119
}
30563120

30573121
class _HelperBox extends RenderBox {
3058-
@protected
3059-
@mustCallSuper
3060-
void updateParentData() {
3061-
_ConstraintBoxData constraintBoxData = parentData as _ConstraintBoxData;
3122+
static void initParentData(_ConstraintBoxData constraintBoxData) {
30623123
constraintBoxData.width = 0;
30633124
constraintBoxData.height = 0;
30643125
constraintBoxData.clickPadding = EdgeInsets.zero;
@@ -3095,6 +3156,13 @@ class _HelperBox extends RenderBox {
30953156
constraintBoxData._isBarrier = false;
30963157
constraintBoxData._helperSize = null;
30973158
}
3159+
3160+
@protected
3161+
@mustCallSuper
3162+
void updateParentData() {
3163+
_ConstraintBoxData constraintBoxData = parentData as _ConstraintBoxData;
3164+
initParentData(constraintBoxData);
3165+
}
30983166
}
30993167

31003168
class GuidelineDefine extends ConstraintDefine {
@@ -3192,10 +3260,10 @@ class Guideline extends LeafRenderObjectWidget {
31923260

31933261
class _GuidelineRenderBox extends _HelperBox {
31943262
late ConstraintId _id;
3263+
late bool _horizontal;
31953264
double? _guidelineBegin;
31963265
double? _guidelineEnd;
31973266
double? _guidelinePercent;
3198-
late bool _horizontal;
31993267

32003268
set id(ConstraintId value) {
32013269
if (_id != value) {
@@ -3242,65 +3310,107 @@ class _GuidelineRenderBox extends _HelperBox {
32423310
void updateParentData() {
32433311
super.updateParentData();
32443312
_ConstraintBoxData constraintBoxData = parentData as _ConstraintBoxData;
3245-
constraintBoxData.id = _id;
3246-
constraintBoxData._isGuideline = true;
3313+
initParentData(
3314+
constraintBoxData,
3315+
id: _id,
3316+
horizontal: _horizontal,
3317+
guidelineBegin: _guidelineBegin,
3318+
guidelineEnd: _guidelineEnd,
3319+
guidelinePercent: _guidelinePercent,
3320+
);
3321+
}
3322+
3323+
@override
3324+
void performLayout() {
32473325
if (_horizontal) {
3248-
if (_guidelineBegin != null) {
3326+
size = Size(constraints.minWidth, 0);
3327+
} else {
3328+
size = Size(0, constraints.minHeight);
3329+
}
3330+
}
3331+
3332+
static void initParentData(
3333+
_ConstraintBoxData constraintBoxData, {
3334+
required ConstraintId id,
3335+
required bool horizontal,
3336+
double? guidelineBegin,
3337+
double? guidelineEnd,
3338+
double? guidelinePercent,
3339+
}) {
3340+
constraintBoxData.id = id;
3341+
constraintBoxData._isGuideline = true;
3342+
if (horizontal) {
3343+
if (guidelineBegin != null) {
32493344
constraintBoxData.left = parent.left;
32503345
constraintBoxData.top = parent.top;
32513346
constraintBoxData.right = parent.right;
32523347
constraintBoxData.width = matchParent;
3253-
constraintBoxData.margin = EdgeInsets.only(top: _guidelineBegin!);
3254-
} else if (_guidelineEnd != null) {
3348+
constraintBoxData.margin = EdgeInsets.only(top: guidelineBegin);
3349+
} else if (guidelineEnd != null) {
32553350
constraintBoxData.left = parent.left;
32563351
constraintBoxData.right = parent.right;
32573352
constraintBoxData.bottom = parent.bottom;
32583353
constraintBoxData.width = matchParent;
3259-
constraintBoxData.margin = EdgeInsets.only(bottom: _guidelineEnd!);
3354+
constraintBoxData.margin = EdgeInsets.only(bottom: guidelineEnd);
32603355
} else {
32613356
constraintBoxData.left = parent.left;
32623357
constraintBoxData.top = parent.top;
32633358
constraintBoxData.right = parent.right;
32643359
constraintBoxData.width = matchParent;
32653360
constraintBoxData.margin = EdgeInsets.only(
3266-
top: _guidelinePercent!,
3361+
top: guidelinePercent!,
32673362
);
32683363
constraintBoxData.percentageMargin = true;
32693364
}
32703365
} else {
3271-
if (_guidelineBegin != null) {
3366+
if (guidelineBegin != null) {
32723367
constraintBoxData.left = parent.left;
32733368
constraintBoxData.top = parent.top;
32743369
constraintBoxData.bottom = parent.bottom;
32753370
constraintBoxData.height = matchParent;
3276-
constraintBoxData.margin = EdgeInsets.only(left: _guidelineBegin!);
3277-
} else if (_guidelineEnd != null) {
3371+
constraintBoxData.margin = EdgeInsets.only(left: guidelineBegin);
3372+
} else if (guidelineEnd != null) {
32783373
constraintBoxData.top = parent.top;
32793374
constraintBoxData.right = parent.right;
32803375
constraintBoxData.bottom = parent.bottom;
32813376
constraintBoxData.height = matchParent;
3282-
constraintBoxData.margin = EdgeInsets.only(right: _guidelineEnd!);
3377+
constraintBoxData.margin = EdgeInsets.only(right: guidelineEnd);
32833378
} else {
32843379
constraintBoxData.left = parent.left;
32853380
constraintBoxData.top = parent.top;
32863381
constraintBoxData.bottom = parent.bottom;
32873382
constraintBoxData.height = matchParent;
32883383
constraintBoxData.margin = EdgeInsets.only(
3289-
left: _guidelinePercent!,
3384+
left: guidelinePercent!,
32903385
);
32913386
constraintBoxData.percentageMargin = true;
32923387
}
32933388
}
32943389
}
3390+
}
3391+
3392+
class BarrierDefine extends ConstraintDefine {
3393+
final BarrierDirection direction;
3394+
final List<ConstraintId> referencedIds;
3395+
3396+
BarrierDefine({
3397+
required ConstraintId id,
3398+
required this.direction,
3399+
required this.referencedIds,
3400+
}) : super(id);
32953401

32963402
@override
3297-
void performLayout() {
3298-
if (_horizontal) {
3299-
size = Size(constraints.minWidth, 0);
3300-
} else {
3301-
size = Size(0, constraints.minHeight);
3302-
}
3303-
}
3403+
bool operator ==(Object other) =>
3404+
identical(this, other) ||
3405+
super == other &&
3406+
other is BarrierDefine &&
3407+
runtimeType == other.runtimeType &&
3408+
direction == other.direction &&
3409+
referencedIds == other.referencedIds;
3410+
3411+
@override
3412+
int get hashCode =>
3413+
super.hashCode ^ direction.hashCode ^ referencedIds.hashCode;
33043414
}
33053415

33063416
class Barrier extends LeafRenderObjectWidget {
@@ -3354,24 +3464,12 @@ class _BarrierRenderBox extends _HelperBox {
33543464
void updateParentData() {
33553465
super.updateParentData();
33563466
_ConstraintBoxData constraintBoxData = parentData as _ConstraintBoxData;
3357-
constraintBoxData.id = _id;
3358-
constraintBoxData._isBarrier = true;
3359-
constraintBoxData._direction = _direction;
3360-
constraintBoxData._referencedIds = _referencedIds;
3361-
if (_direction == BarrierDirection.top ||
3362-
_direction == BarrierDirection.bottom) {
3363-
constraintBoxData.width = matchParent;
3364-
constraintBoxData.height = 0;
3365-
constraintBoxData.top = parent.top;
3366-
constraintBoxData.left = parent.left;
3367-
constraintBoxData.right = parent.right;
3368-
} else {
3369-
constraintBoxData.width = 0;
3370-
constraintBoxData.height = matchParent;
3371-
constraintBoxData.left = parent.left;
3372-
constraintBoxData.top = parent.top;
3373-
constraintBoxData.bottom = parent.bottom;
3374-
}
3467+
initParentData(
3468+
constraintBoxData,
3469+
id: _id,
3470+
direction: _direction,
3471+
referencedIds: _referencedIds,
3472+
);
33753473
}
33763474

33773475
set id(ConstraintId value) {
@@ -3420,6 +3518,32 @@ class _BarrierRenderBox extends _HelperBox {
34203518
size = Size(0, constraints.minHeight);
34213519
}
34223520
}
3521+
3522+
static void initParentData(
3523+
_ConstraintBoxData constraintBoxData, {
3524+
required ConstraintId id,
3525+
required BarrierDirection direction,
3526+
required List<ConstraintId> referencedIds,
3527+
}) {
3528+
constraintBoxData.id = id;
3529+
constraintBoxData._isBarrier = true;
3530+
constraintBoxData._direction = direction;
3531+
constraintBoxData._referencedIds = referencedIds;
3532+
if (direction == BarrierDirection.top ||
3533+
direction == BarrierDirection.bottom) {
3534+
constraintBoxData.width = matchParent;
3535+
constraintBoxData.height = 0;
3536+
constraintBoxData.top = parent.top;
3537+
constraintBoxData.left = parent.left;
3538+
constraintBoxData.right = parent.right;
3539+
} else {
3540+
constraintBoxData.width = 0;
3541+
constraintBoxData.height = matchParent;
3542+
constraintBoxData.left = parent.left;
3543+
constraintBoxData.top = parent.top;
3544+
constraintBoxData.bottom = parent.bottom;
3545+
}
3546+
}
34233547
}
34243548

34253549
class ConstraintLayoutException implements Exception {

0 commit comments

Comments
 (0)