From 763bb6214f3a867b2e56bac064dc186713e3ef39 Mon Sep 17 00:00:00 2001 From: hackware1993 Date: Wed, 11 May 2022 23:34:10 +0800 Subject: [PATCH 1/4] add pinned position support --- example/home.dart | 2 + example/pinned_position.dart | 40 ++++++++ lib/src/constraint_layout.dart | 177 ++++++++++++++++++++++++++++++++- pubspec.yaml | 3 +- 4 files changed, 217 insertions(+), 5 deletions(-) create mode 100644 example/pinned_position.dart diff --git a/example/home.dart b/example/home.dart index 03feb9c..da22c5f 100644 --- a/example/home.dart +++ b/example/home.dart @@ -13,6 +13,7 @@ import 'guideline.dart'; import 'horizontal_list.dart'; import 'margin.dart'; import 'percentage_layout.dart'; +import 'pinned_position.dart'; import 'relative_id.dart'; import 'self_wrap_content.dart'; import 'staggered_grid.dart'; @@ -38,6 +39,7 @@ class ExampleHome extends StatelessWidget { 'Vertical List': const VerticalListExample(), 'Staggered Grid': const StaggeredGridExample(), 'Circle Position': const CirclePositionExample(), + 'Pinned Position': const PinnedPositionExample(), 'Self wrapContent': const SelfWrapContentExample(), 'Margin': const MarginExample(), 'Charts': const ChartsExample(), diff --git a/example/pinned_position.dart b/example/pinned_position.dart new file mode 100644 index 0000000..7ec1477 --- /dev/null +++ b/example/pinned_position.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_constraintlayout/src/constraint_layout.dart'; + +import 'custom_app_bar.dart'; + +class PinnedPositionExample extends StatelessWidget { + const PinnedPositionExample({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + ConstraintId anchor = ConstraintId('anchor'); + return Scaffold( + appBar: const CustomAppBar( + title: 'Pinned Position', + codePath: 'example/pinned_position.dart', + ), + body: ConstraintLayout( + children: [ + Container( + color: Colors.yellow, + ).applyConstraint( + id: anchor, + size: 200, + centerTo: parent, + ), + Container( + color: Colors.cyan, + ).applyConstraint( + size: 40, + pinnedInfo: PinnedInfo( + anchor, + PinnedPos(0, PinnedType.absolute, 0.5, PinnedType.percent), + PinnedPos(0.5, PinnedType.percent, 0.5, PinnedType.percent), + ), + ) + ], + ), + ); + } +} diff --git a/lib/src/constraint_layout.dart b/lib/src/constraint_layout.dart index e415071..d589a7e 100644 --- a/lib/src/constraint_layout.dart +++ b/lib/src/constraint_layout.dart @@ -459,6 +459,7 @@ extension ConstrainedWidgetsExt on Widget { double? widthHeightRatio, bool? ratioBaseOnWidth, int? eIndex, + PinnedInfo? pinnedInfo, }) { return Constrained( key: key, @@ -524,6 +525,7 @@ extension ConstrainedWidgetsExt on Widget { centerBottomCenterTo: centerBottomCenterTo, centerBottomRightTo: centerBottomRightTo, eIndex: eIndex, + pinnedInfo: pinnedInfo, ), child: this, ); @@ -934,6 +936,95 @@ class ConstraintDefine { int get hashCode => id.hashCode; } +enum PinnedType { + absolute, + percent, +} + +class PinnedPos { + double xOffset; + PinnedType xType; + double yOffset; + PinnedType yType; + + PinnedPos(this.xOffset, this.xType, this.yOffset, this.yType); + + void checkBounds(double value, PinnedType pinnedType, double base) { + if (pinnedType == PinnedType.absolute) { + assert(value >= 0 && value <= base); + } else { + assert(value >= 0 && value <= 1); + } + } + + Offset resolve(Size size) { + assert(() { + checkBounds(xOffset, xType, size.width); + checkBounds(yOffset, yType, size.height); + return true; + }()); + double x; + double y; + if (xType == PinnedType.absolute) { + x = xOffset; + } else { + x = xOffset * size.width; + } + if (yType == PinnedType.absolute) { + y = yOffset; + } else { + y = yOffset * size.height; + } + return Offset(x, y); + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is PinnedPos && + runtimeType == other.runtimeType && + xOffset == other.xOffset && + xType == other.xType && + yOffset == other.yOffset && + yType == other.yType; + + @override + int get hashCode => + xOffset.hashCode ^ xType.hashCode ^ yOffset.hashCode ^ yType.hashCode; +} + +class PinnedInfo { + /// [0,360] + int rotateDegree; + ConstraintId anchorId; + PinnedPos selfPos; + PinnedPos targetPos; + + PinnedInfo( + this.anchorId, + this.selfPos, + this.targetPos, { + this.rotateDegree = 0, + }); + + @override + bool operator ==(Object other) => + identical(this, other) || + other is PinnedInfo && + runtimeType == other.runtimeType && + rotateDegree == other.rotateDegree && + anchorId == other.anchorId && + selfPos == other.selfPos && + targetPos == other.targetPos; + + @override + int get hashCode => + rotateDegree.hashCode ^ + anchorId.hashCode ^ + selfPos.hashCode ^ + targetPos.hashCode; +} + class Constraint extends ConstraintDefine { /// 'wrap_content'、'match_parent'、'match_constraint'、'48, etc' /// 'match_parent' will be converted to the base constraints @@ -1073,6 +1164,8 @@ class Constraint extends ConstraintDefine { final int? eIndex; + final PinnedInfo? pinnedInfo; + Constraint({ ConstraintId? id, this.width = wrapContent, @@ -1135,6 +1228,7 @@ class Constraint extends ConstraintDefine { this.widthHeightRatio, this.ratioBaseOnWidth, this.eIndex, + this.pinnedInfo, }) : super(id); @override @@ -1201,7 +1295,8 @@ class Constraint extends ConstraintDefine { maxHeight == other.maxHeight && widthHeightRatio == other.widthHeightRatio && ratioBaseOnWidth == other.ratioBaseOnWidth && - eIndex == other.eIndex; + eIndex == other.eIndex && + pinnedInfo == other.pinnedInfo; @override int get hashCode => @@ -1264,7 +1359,8 @@ class Constraint extends ConstraintDefine { maxHeight.hashCode ^ widthHeightRatio.hashCode ^ ratioBaseOnWidth.hashCode ^ - eIndex.hashCode; + eIndex.hashCode ^ + pinnedInfo.hashCode; bool checkSize(double size) { if (size == matchParent || size == wrapContent || size == matchConstraint) { @@ -1801,6 +1897,25 @@ class Constraint extends ConstraintDefine { needsReorderEventOrder = true; } + if (parentData.pinnedInfo != pinnedInfo) { + if (parentData.pinnedInfo == null || pinnedInfo == null) { + needsRecalculateConstraints = true; + needsLayout = true; + } else { + if (parentData.pinnedInfo!.anchorId != pinnedInfo!.anchorId) { + needsRecalculateConstraints = true; + needsLayout = true; + } else if (parentData.pinnedInfo!.selfPos != pinnedInfo!.selfPos || + parentData.pinnedInfo!.targetPos != pinnedInfo!.targetPos) { + needsLayout = true; + } else if (parentData.pinnedInfo!.rotateDegree != + pinnedInfo!.rotateDegree) { + needsPaint = true; + } + } + parentData.pinnedInfo = pinnedInfo; + } + if (needsLayout) { AbstractNode? targetParent = renderObject.parent; if (needsRecalculateConstraints) { @@ -1875,6 +1990,7 @@ class _ConstraintBoxData extends ContainerBoxParentData { double? widthHeightRatio; bool? ratioBaseOnWidth; int? eIndex; + PinnedInfo? pinnedInfo; // for internal use late Map _constrainedNodeMap; @@ -2227,6 +2343,9 @@ class _ConstraintRenderBox extends RenderBox if (child is _BarrierRenderBox) { constraintsIdSet.addAll(childParentData._referencedIds!); } + if (childParentData.pinnedInfo != null) { + constraintsIdSet.add(childParentData.pinnedInfo!.anchorId); + } child = childParentData.nextSibling; } @@ -2265,6 +2384,18 @@ class _ConstraintRenderBox extends RenderBox /// Each child element must have complete constraints both horizontally and vertically static void _debugCheckConstraintsIntegrity(List<_ConstrainedNode> nodeList) { for (final element in nodeList) { + if (element.pinnedInfo != null) { + if (element.width != wrapContent && element.width < 0) { + throw ConstraintLayoutException( + 'When setting pinnedInfo, width and height must be wrapContent or fixed size.'); + } + if (element.height != wrapContent && element.height < 0) { + throw ConstraintLayoutException( + 'When setting pinnedInfo, width and height must be wrapContent or fixed size.'); + } + continue; + } + /// Check constraint integrity in the horizontal direction if (element.width == wrapContent || element.width >= 0) { if (element.leftConstraint == null && element.rightConstraint == null) { @@ -2492,6 +2623,11 @@ class _ConstraintRenderBox extends RenderBox currentNode.baselineAlignType = childParentData.baseline!.type; } + if (childParentData.pinnedInfo != null) { + currentNode.pinnedConstraint = _getConstrainedNodeForChild( + childParentData.pinnedInfo!.anchorId, childIndex); + } + child = childParentData.nextSibling; } @@ -2814,7 +2950,7 @@ class _ConstraintRenderBox extends RenderBox } else if (sizeConfirmedChild.rightConstraint != null) { childSpanWidth += size.width - sizeConfirmedChild.getRight(); } else { - /// It is not possible to execute this branch + childSpanWidth += sizeConfirmedChild.getX(); } if (sizeConfirmedChild.topConstraint != null && @@ -2824,7 +2960,7 @@ class _ConstraintRenderBox extends RenderBox } else if (sizeConfirmedChild.bottomConstraint != null) { childSpanHeight += size.height - sizeConfirmedChild.getBottom(); } else { - /// It is not possible to execute this branch + childSpanHeight += sizeConfirmedChild.getY(); } if (childSpanWidth > contentWidth) { @@ -3190,6 +3326,18 @@ class _ConstraintRenderBox extends RenderBox } Offset calculateChildOffset(_ConstrainedNode node) { + if (node.pinnedInfo != null) { + PinnedInfo pinnedInfo = node.pinnedInfo!; + Offset selfOffset = pinnedInfo.selfPos.resolve(node.renderBox!.size); + Offset targetOffset = + pinnedInfo.targetPos.resolve(node.pinnedConstraint!.getSize(this)); + double offsetX = + node.pinnedConstraint!.getX() + targetOffset.dx - selfOffset.dx; + double offsetY = + node.pinnedConstraint!.getY() + targetOffset.dy - selfOffset.dy; + return Offset(offsetX, offsetY); + } + EdgeInsets margin = node.margin; EdgeInsets goneMargin = node.goneMargin; double offsetX = 0; @@ -3730,6 +3878,7 @@ class _ConstrainedNode { _ConstrainedNode? rightConstraint; _ConstrainedNode? bottomConstraint; _ConstrainedNode? baselineConstraint; + _ConstrainedNode? pinnedConstraint; _AlignType? leftAlignType; _AlignType? topAlignType; _AlignType? rightAlignType; @@ -3823,6 +3972,8 @@ class _ConstrainedNode { Size? get helperSize => parentData._helperSize; + PinnedInfo? get pinnedInfo => parentData.pinnedInfo; + set helperSize(Size? size) { parentData._helperSize = size; } @@ -3886,6 +4037,13 @@ class _ConstrainedNode { return getY() + getMeasuredHeight(); } + Size getSize([RenderBox? parent]) { + if (isParent()) { + return parent!.size; + } + return renderBox!.size; + } + double getMeasuredWidth() { if (isGuideline || isBarrier) { return helperSize!.width; @@ -3975,6 +4133,9 @@ class _ConstrainedNode { if (baselineConstraint != null) getDepthFor(baselineConstraint!, parentSizeConfirmed, resolvedWidth, resolvedHeight), + if (pinnedConstraint != null) + getDepthFor(pinnedConstraint!, parentSizeConfirmed, resolvedWidth, + resolvedHeight), ]; depth = getMaxDepth(list) + 1; } @@ -4051,6 +4212,13 @@ class _ConstrainedNode { map['baselineConstraint'] = baselineConstraint!.toJson(); } } + if (pinnedConstraint != null) { + if (pinnedConstraint!.isParent()) { + map['pinnedConstraint'] = 'parent'; + } else { + map['pinnedConstraint'] = pinnedConstraint!.toJson(); + } + } } map['depth'] = getDepth(null, null, null); return map; @@ -4090,6 +4258,7 @@ class _HelperBox extends RenderBox { constraintBoxData.widthHeightRatio = null; constraintBoxData.ratioBaseOnWidth = null; constraintBoxData.eIndex = null; + constraintBoxData.pinnedInfo = null; constraintBoxData._direction = null; constraintBoxData._referencedIds = null; constraintBoxData._isGuideline = false; diff --git a/pubspec.yaml b/pubspec.yaml index 701fadf..129ae52 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,4 +38,5 @@ flutter: - example/circle_position.dart - example/self_wrap_content.dart - example/margin.dart - - example/charts.dart \ No newline at end of file + - example/charts.dart + - example/pinned_position.dart \ No newline at end of file From 76619afdecfb6f1bbadc901c67126ae7eb930cc9 Mon Sep 17 00:00:00 2001 From: hackware1993 Date: Wed, 11 May 2022 23:46:50 +0800 Subject: [PATCH 2/4] release v1.1.0-alpha --- CHANGELOG.md | 4 ++++ README.md | 11 ++++++----- README_CN.md | 11 ++++++----- pubspec.yaml | 2 +- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fd7487..27deae4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# v1.1.0-alpha + +add pinned position support. + # v1.0.7-stable optimize key set. diff --git a/README.md b/README.md index c3b70d4..a736510 100644 --- a/README.md +++ b/README.md @@ -136,13 +136,14 @@ two-way constraints, such as chains(not yet supported, please use with Flex). 16. staggered grid、grid、list(list is a special staggered grid, grid is also a special staggered grid) 17. circle position -18. e-index(event dispatch order, default is z-index) -19. the size of child widgets can be set to: +18. pinned position +19. e-index(event dispatch order, default is z-index) +20. the size of child widgets can be set to: 1. fixed size(>=0) 2. matchParent 3. wrapContent(default, minimum and maximum supported) 4. matchConstraint -20. the size of itself can be set to: +21. the size of itself can be set to: 1. fixed size(>=0) 2. matchParent(default) 3. wrapContent(minimum and maximum are temporarily not supported) @@ -171,12 +172,12 @@ dependencies: flutter_constraintlayout: git: url: 'https://github.com/hackware1993/Flutter-ConstraintLayout.git' - ref: 'v1.0.7-stable' + ref: 'v1.1.0-alpha' ``` ```yaml dependencies: - flutter_constraintlayout: ^1.0.7-stable + flutter_constraintlayout: ^1.1.0-alpha ``` ```dart diff --git a/README_CN.md b/README_CN.md index 371ea31..bf5bb81 100644 --- a/README_CN.md +++ b/README_CN.md @@ -110,13 +110,14 @@ build 耗时有时甚至超过渲染耗时。 27. centerBottomRightTo 16. 瀑布流、网格、列表(列表是一个特殊的瀑布流,网格也是一个特殊的瀑布流) 17. 圆形定位 -18. e-index(事件分发顺序,默认是 z-index,一般用来处理点击区域) -19. 子元素的大小可以被设置为: +18. 图钉定位 +19. e-index(事件分发顺序,默认是 z-index,一般用来处理点击区域) +20. 子元素的大小可以被设置为: 1. 固定大小(>=0) 2. matchParent 3. wrapContent(默认值,支持最大、最小设置) 4. matchConstraint -20. 自身的大小可以被设置为: +21. 自身的大小可以被设置为: 1. 固定大小(>=0) 2. matchParent(default) 3. wrapContent(暂不支持最大、最小设置) @@ -145,12 +146,12 @@ dependencies: flutter_constraintlayout: git: url: 'https://github.com/hackware1993/Flutter-ConstraintLayout.git' - ref: 'v1.0.7-stable' + ref: 'v1.1.0-alpha' ``` ```yaml dependencies: - flutter_constraintlayout: ^1.0.7-stable + flutter_constraintlayout: ^1.1.0-alpha ``` ```dart diff --git a/pubspec.yaml b/pubspec.yaml index 129ae52..91c64d5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_constraintlayout description: A super powerful Stack, build flexible layouts with constraints. Similar to ConstraintLayout for Android and AutoLayout for iOS. -version: 1.0.7-stable +version: 1.1.0-alpha anthor: hackware homepage: https://github.com/hackware1993/Flutter-ConstraintLayout From 463be96e6fdbdc03c5759c2e5164fae83cf4ecd4 Mon Sep 17 00:00:00 2001 From: fbchen Date: Thu, 12 May 2022 09:46:56 +0800 Subject: [PATCH 3/4] add constraint version control --- lib/src/constraint_layout.dart | 164 +++++++++++++++++++++++++++++---- 1 file changed, 148 insertions(+), 16 deletions(-) diff --git a/lib/src/constraint_layout.dart b/lib/src/constraint_layout.dart index d589a7e..3f3bbaf 100644 --- a/lib/src/constraint_layout.dart +++ b/lib/src/constraint_layout.dart @@ -31,6 +31,8 @@ class ConstraintLayout extends MultiChildRenderObjectWidget { /// When size is non-null, both width and height are set to size final double? size; + final ConstraintVersion? constraintVersion; + ConstraintLayout({ Key? key, this.childConstraints, @@ -47,6 +49,7 @@ class ConstraintLayout extends MultiChildRenderObjectWidget { this.width = matchParent, this.height = matchParent, this.size, + this.constraintVersion, }) : super( key: key, children: children, @@ -77,7 +80,8 @@ class ConstraintLayout extends MultiChildRenderObjectWidget { .._debugShowZIndex = debugShowZIndex .._debugShowChildDepth = debugShowChildDepth .._width = selfWidth - .._height = selfHeight; + .._height = selfHeight + .._constraintVersion = constraintVersion?.copy(); } @override @@ -108,7 +112,8 @@ class ConstraintLayout extends MultiChildRenderObjectWidget { ..debugShowZIndex = debugShowZIndex ..debugShowChildDepth = debugShowChildDepth ..width = selfWidth - ..height = selfHeight; + ..height = selfHeight + ..constraintVersion = constraintVersion?.copy(); } } @@ -1025,6 +1030,68 @@ class PinnedInfo { targetPos.hashCode; } +class ConstraintVersion { + int _constraintsVersion = 1; + int _layoutVersion = 1; + int _paintVersion = 1; + int _paintingOrderVersion = 1; + int _eventOrderVersion = 1; + + ConstraintVersion incConstraintsVersion() { + _constraintsVersion++; + return this; + } + + ConstraintVersion incLayoutVersion() { + _layoutVersion++; + return this; + } + + ConstraintVersion incPaintVersion() { + _paintVersion++; + return this; + } + + ConstraintVersion incPaintingOrderVersion() { + _paintingOrderVersion++; + _eventOrderVersion++; + return this; + } + + ConstraintVersion incEventOrderVersion() { + _eventOrderVersion++; + return this; + } + + ConstraintVersion copy() { + return ConstraintVersion() + .._constraintsVersion = _constraintsVersion + .._layoutVersion = _layoutVersion + .._paintVersion = _paintVersion + .._paintingOrderVersion = _paintingOrderVersion + .._eventOrderVersion = _eventOrderVersion; + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is ConstraintVersion && + runtimeType == other.runtimeType && + _constraintsVersion == other._constraintsVersion && + _layoutVersion == other._layoutVersion && + _paintVersion == other._paintVersion && + _paintingOrderVersion == other._paintingOrderVersion && + _eventOrderVersion == other._eventOrderVersion; + + @override + int get hashCode => + _constraintsVersion.hashCode ^ + _layoutVersion.hashCode ^ + _paintVersion.hashCode ^ + _paintingOrderVersion.hashCode ^ + _eventOrderVersion.hashCode; +} + class Constraint extends ConstraintDefine { /// 'wrap_content'、'match_parent'、'match_constraint'、'48, etc' /// 'match_parent' will be converted to the base constraints @@ -1422,6 +1489,16 @@ class Constraint extends ConstraintDefine { return true; } + static int getMinimalConstraintCount(double size) { + if (size == matchParent) { + return 0; + } else if (size == wrapContent || size >= 0) { + return 1; + } else { + return 2; + } + } + void applyTo(RenderObject renderObject) { _Align? left = this.left; _Align? top = this.top; @@ -1697,6 +1774,45 @@ class Constraint extends ConstraintDefine { _ConstraintBoxData parentData = renderObject.parentData! as _ConstraintBoxData; + parentData.clickPadding = clickPadding; + parentData.callback = callback; + + if ((renderObject.parent as _ConstraintRenderBox)._constraintVersion != + null) { + parentData.id = id; + parentData.width = width; + parentData.height = height; + parentData.visibility = visibility; + parentData.percentageMargin = percentageMargin; + parentData.margin = margin; + parentData.goneMargin = goneMargin; + parentData.left = left; + parentData.right = right; + parentData.top = top; + parentData.bottom = bottom; + parentData.baseline = baseline; + parentData.textBaseline = textBaseline; + parentData.zIndex = zIndex; + parentData.translateConstraint = translateConstraint; + parentData.translate = translate; + parentData.widthPercent = widthPercent; + parentData.heightPercent = heightPercent; + parentData.widthPercentageAnchor = widthPercentageAnchor; + parentData.heightPercentageAnchor = heightPercentageAnchor; + parentData.horizontalBias = horizontalBias; + parentData.verticalBias = verticalBias; + parentData.percentageTranslate = percentageTranslate; + parentData.minWidth = minWidth; + parentData.maxWidth = maxWidth; + parentData.minHeight = minHeight; + parentData.maxHeight = maxHeight; + parentData.widthHeightRatio = widthHeightRatio; + parentData.ratioBaseOnWidth = ratioBaseOnWidth; + parentData.eIndex = eIndex; + parentData.pinnedInfo = pinnedInfo; + return; + } + bool needsLayout = false; bool needsPaint = false; bool needsReorderPaintingOrder = false; @@ -1709,16 +1825,6 @@ class Constraint extends ConstraintDefine { needsLayout = true; } - int getMinimalConstraintCount(double size) { - if (size == matchParent) { - return 0; - } else if (size == wrapContent || size >= 0) { - return 1; - } else { - return 2; - } - } - if (parentData.width != width) { needsRecalculateConstraints = true; if (parentData.width != null) { @@ -1743,8 +1849,6 @@ class Constraint extends ConstraintDefine { needsLayout = true; } - parentData.clickPadding = clickPadding; - if (parentData.visibility != visibility) { if (parentData.visibility == gone || visibility == gone) { needsLayout = true; @@ -1855,8 +1959,6 @@ class Constraint extends ConstraintDefine { needsLayout = true; } - parentData.callback = callback; - if (parentData.percentageTranslate != percentageTranslate) { parentData.percentageTranslate = percentageTranslate; needsPaint = true; @@ -2095,6 +2197,7 @@ class _ConstraintRenderBox extends RenderBox late double _width; late double _height; + ConstraintVersion? _constraintVersion; bool _needsRecalculateConstraints = true; bool _needsReorderPaintingOrder = true; @@ -2283,6 +2386,35 @@ class _ConstraintRenderBox extends RenderBox } } + set constraintVersion(ConstraintVersion? value) { + if (_constraintVersion == null || value == null) { + markNeedsRecalculateConstraints(); + markNeedsLayout(); + } else { + if (_constraintVersion!._constraintsVersion != + value._constraintsVersion) { + markNeedsRecalculateConstraints(); + markNeedsLayout(); + } else { + if (_constraintVersion!._layoutVersion != value._layoutVersion) { + markNeedsLayout(); + } + if (_constraintVersion!._paintingOrderVersion != + value._paintingOrderVersion) { + needsReorderPaintingOrder = true; + } + if (_constraintVersion!._paintVersion != value._paintVersion) { + markNeedsPaint(); + } + if (_constraintVersion!._eventOrderVersion != + value._eventOrderVersion) { + needsReorderEventOrder = true; + } + } + } + _constraintVersion = value; + } + @override void setupParentData(covariant RenderObject child) { if (child.parentData is! _ConstraintBoxData) { From 406c9897273c8e9a9052d5f91a579a36e4c006c6 Mon Sep 17 00:00:00 2001 From: fbchen Date: Thu, 12 May 2022 11:43:25 +0800 Subject: [PATCH 4/4] fully support pinned position --- example/pinned_position.dart | 1 + lib/src/constraint_layout.dart | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/example/pinned_position.dart b/example/pinned_position.dart index 7ec1477..224379f 100644 --- a/example/pinned_position.dart +++ b/example/pinned_position.dart @@ -31,6 +31,7 @@ class PinnedPositionExample extends StatelessWidget { anchor, PinnedPos(0, PinnedType.absolute, 0.5, PinnedType.percent), PinnedPos(0.5, PinnedType.percent, 0.5, PinnedType.percent), + rotateDegree: 45, ), ) ], diff --git a/lib/src/constraint_layout.dart b/lib/src/constraint_layout.dart index 3f3bbaf..f25b109 100644 --- a/lib/src/constraint_layout.dart +++ b/lib/src/constraint_layout.dart @@ -3777,8 +3777,29 @@ class _ConstraintRenderBox extends RenderBox if (!element.translateConstraint) { paintShift = element.translate; } - context.paintChild( - element.renderBox!, element.offset + offset + paintShift); + + if (element.pinnedInfo != null) { + context.canvas.save(); + context.canvas.translate( + element.offset.dx + + offset.dx + + paintShift.dx + + element.getMeasuredWidth() / 2, + element.offset.dy + + offset.dy + + paintShift.dy + + element.getMeasuredHeight() / 2); + context.canvas + .rotate(pi + pi * (element.pinnedInfo!.rotateDegree / 180)); + context.paintChild( + element.renderBox!, + Offset(-element.getMeasuredWidth() / 2, + -element.getMeasuredHeight() / 2)); + context.canvas.restore(); + } else { + context.paintChild( + element.renderBox!, element.offset + offset + paintShift); + } /// Draw child's click area assert(() {