Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ASCornerLayoutSpec] New layout spec class for declarative corner element layout. #657

Merged
merged 7 commits into from
Nov 24, 2017
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions AsyncDisplayKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
05EA6FE71AC0966E00E35788 /* ASSnapshotTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 05EA6FE61AC0966E00E35788 /* ASSnapshotTestCase.m */; };
18C2ED7F1B9B7DE800F627B3 /* ASCollectionNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
18C2ED831B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */; };
1A6C000D1FAB4E2100D05926 /* ASCornerLayoutSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A6C000B1FAB4E2000D05926 /* ASCornerLayoutSpec.h */; settings = {ATTRIBUTES = (Public, ); }; };
1A6C000E1FAB4E2100D05926 /* ASCornerLayoutSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A6C000C1FAB4E2100D05926 /* ASCornerLayoutSpec.mm */; };
1A6C00111FAB4EDD00D05926 /* ASCornerLayoutSpecSnapshotTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A6C000F1FAB4ED400D05926 /* ASCornerLayoutSpecSnapshotTests.mm */; };
242995D31B29743C00090100 /* ASBasicImageDownloaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 242995D21B29743C00090100 /* ASBasicImageDownloaderTests.m */; };
2538B6F31BC5D2A2003CA0B4 /* ASCollectionViewFlowLayoutInspectorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2538B6F21BC5D2A2003CA0B4 /* ASCollectionViewFlowLayoutInspectorTests.m */; };
254C6B521BF8FE6D003EC431 /* ASTextKitTruncationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 254C6B511BF8FE6D003EC431 /* ASTextKitTruncationTests.mm */; };
Expand Down Expand Up @@ -307,8 +310,8 @@
B350625C1B010F070018CF92 /* ASLog.h in Headers */ = {isa = PBXBuildFile; fileRef = 0516FA3B1A15563400B4EBED /* ASLog.h */; settings = {ATTRIBUTES = (Public, ); }; };
B350625D1B0111740018CF92 /* Photos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 051943141A1575670030A7D0 /* Photos.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
B350625E1B0111780018CF92 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 051943121A1575630030A7D0 /* AssetsLibrary.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
BB5FC3D11F9C9389007F191E /* ASTabBarControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BB5FC3D01F9C9389007F191E /* ASTabBarControllerTests.m */; };
BB5FC3CE1F9BA689007F191E /* ASNavigationControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BB5FC3CD1F9BA688007F191E /* ASNavigationControllerTests.m */; };
BB5FC3D11F9C9389007F191E /* ASTabBarControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BB5FC3D01F9C9389007F191E /* ASTabBarControllerTests.m */; };
C78F7E2B1BF7809800CDEAFC /* ASTableNode.h in Headers */ = {isa = PBXBuildFile; fileRef = B0F880581BEAEC7500D17647 /* ASTableNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
CC034A091E60BEB400626263 /* ASDisplayNode+Convenience.h in Headers */ = {isa = PBXBuildFile; fileRef = CC034A071E60BEB400626263 /* ASDisplayNode+Convenience.h */; settings = {ATTRIBUTES = (Public, ); }; };
CC034A0A1E60BEB400626263 /* ASDisplayNode+Convenience.m in Sources */ = {isa = PBXBuildFile; fileRef = CC034A081E60BEB400626263 /* ASDisplayNode+Convenience.m */; };
Expand Down Expand Up @@ -572,6 +575,9 @@
18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionNode.h; sourceTree = "<group>"; };
18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASCollectionNode.mm; sourceTree = "<group>"; };
1950C4481A3BB5C1005C8279 /* ASEqualityHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASEqualityHelpers.h; sourceTree = "<group>"; };
1A6C000B1FAB4E2000D05926 /* ASCornerLayoutSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCornerLayoutSpec.h; sourceTree = "<group>"; };
1A6C000C1FAB4E2100D05926 /* ASCornerLayoutSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASCornerLayoutSpec.mm; sourceTree = "<group>"; };
1A6C000F1FAB4ED400D05926 /* ASCornerLayoutSpecSnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASCornerLayoutSpecSnapshotTests.mm; sourceTree = "<group>"; };
205F0E0D1B371875007741D0 /* UICollectionViewLayout+ASConvenience.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UICollectionViewLayout+ASConvenience.h"; sourceTree = "<group>"; };
205F0E0E1B371875007741D0 /* UICollectionViewLayout+ASConvenience.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UICollectionViewLayout+ASConvenience.m"; sourceTree = "<group>"; };
205F0E111B371BD7007741D0 /* ASScrollDirection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASScrollDirection.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -785,8 +791,8 @@
B30BF6501C5964B0004FCD53 /* ASLayoutManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutManager.h; path = TextKit/ASLayoutManager.h; sourceTree = "<group>"; };
B30BF6511C5964B0004FCD53 /* ASLayoutManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASLayoutManager.m; path = TextKit/ASLayoutManager.m; sourceTree = "<group>"; };
B35061DA1B010EDF0018CF92 /* AsyncDisplayKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AsyncDisplayKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BB5FC3D01F9C9389007F191E /* ASTabBarControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ASTabBarControllerTests.m; sourceTree = "<group>"; };
BB5FC3CD1F9BA688007F191E /* ASNavigationControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ASNavigationControllerTests.m; sourceTree = "<group>"; };
BB5FC3D01F9C9389007F191E /* ASTabBarControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ASTabBarControllerTests.m; sourceTree = "<group>"; };
BDC2D162BD55A807C1475DA5 /* Pods-AsyncDisplayKitTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsyncDisplayKitTests.profile.xcconfig"; path = "Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests.profile.xcconfig"; sourceTree = "<group>"; };
CC034A071E60BEB400626263 /* ASDisplayNode+Convenience.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASDisplayNode+Convenience.h"; sourceTree = "<group>"; };
CC034A081E60BEB400626263 /* ASDisplayNode+Convenience.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ASDisplayNode+Convenience.m"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1187,6 +1193,7 @@
7AB338681C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm */,
ACF6ED551B178DC700DA7C62 /* ASInsetLayoutSpecSnapshotTests.mm */,
ACF6ED591B178DC700DA7C62 /* ASOverlayLayoutSpecSnapshotTests.mm */,
1A6C000F1FAB4ED400D05926 /* ASCornerLayoutSpecSnapshotTests.mm */,
696FCB301D6E46050093471E /* ASBackgroundLayoutSpecSnapshotTests.mm */,
ACF6ED5A1B178DC700DA7C62 /* ASRatioLayoutSpecSnapshotTests.mm */,
ACF6ED5B1B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm */,
Expand Down Expand Up @@ -1524,6 +1531,8 @@
ACF6ED021B17843500DA7C62 /* ASBackgroundLayoutSpec.mm */,
ACF6ED031B17843500DA7C62 /* ASCenterLayoutSpec.h */,
ACF6ED041B17843500DA7C62 /* ASCenterLayoutSpec.mm */,
1A6C000B1FAB4E2000D05926 /* ASCornerLayoutSpec.h */,
1A6C000C1FAB4E2100D05926 /* ASCornerLayoutSpec.mm */,
ACF6ED071B17843500DA7C62 /* ASDimension.h */,
ACF6ED081B17843500DA7C62 /* ASDimension.mm */,
690C35631E055C7B00069B91 /* ASDimensionInternal.h */,
Expand Down Expand Up @@ -1717,6 +1726,7 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
1A6C000D1FAB4E2100D05926 /* ASCornerLayoutSpec.h in Headers */,
E54E00721F1D3828000B30D7 /* ASPagerNode+Beta.h in Headers */,
E5B225281F1790D6001E1431 /* ASHashing.h in Headers */,
CC034A131E649F1300626263 /* AsyncDisplayKit+IGListKitMethods.h in Headers */,
Expand Down Expand Up @@ -2069,13 +2079,16 @@
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-AsyncDisplayKitTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
3B9D88CDF51B429C8409E4B6 /* [CP] Copy Pods Resources */ = {
Expand Down Expand Up @@ -2174,6 +2187,7 @@
ACF6ED621B178DC700DA7C62 /* ASRatioLayoutSpecSnapshotTests.mm in Sources */,
7AB338691C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm in Sources */,
CCDD148B1EEDCD9D0020834E /* ASCollectionModernDataSourceTests.m in Sources */,
1A6C00111FAB4EDD00D05926 /* ASCornerLayoutSpecSnapshotTests.mm in Sources */,
254C6B541BF8FF2A003EC431 /* ASTextKitTests.mm in Sources */,
05EA6FE71AC0966E00E35788 /* ASSnapshotTestCase.m in Sources */,
ACF6ED631B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm in Sources */,
Expand Down Expand Up @@ -2334,6 +2348,7 @@
68FC85E51CE29B7E00EDD713 /* ASTabBarController.m in Sources */,
CCCCCCDC1EC3EF060087FE10 /* ASTextLine.m in Sources */,
34EFC7741B701D0A00AD841F /* ASAbsoluteLayoutSpec.mm in Sources */,
1A6C000E1FAB4E2100D05926 /* ASCornerLayoutSpec.mm in Sources */,
CCCCCCE81EC3F0FC0087FE10 /* NSAttributedString+ASText.m in Sources */,
690C35621E055C5D00069B91 /* ASDimensionInternal.mm in Sources */,
909C4C761F09C98B00D6B76F /* ASTextNode2.mm in Sources */,
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- [ASNetworkImageNode] New delegate callback to tell the consumer whether the image was loaded from cache or download. [Adlai Holler](https://github.com/Adlai-Holler)
- [Layout] Fixes a deadlock in layout. [#638](https://github.com/TextureGroup/Texture/pull/638) [Garrett Moon](https://github.com/garrettmoon)
- Updated to be backwards compatible with Xcode 8. [Adlai Holler](https://github.com/Adlai-Holler)
- [ASCornerLayoutSpec] New layout spec class for declarative corner element layout. [#657](https://github.com/TextureGroup/Texture/pull/657) [huangkun](https://github.com/huang-kun)

## 2.6
- [Xcode 9] Updated to require Xcode 9 (to fix warnings) [Garrett Moon](https://github.com/garrettmoon)
Expand Down
1 change: 1 addition & 0 deletions Source/AsyncDisplayKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
#import <AsyncDisplayKit/ASLayoutSpec.h>
#import <AsyncDisplayKit/ASBackgroundLayoutSpec.h>
#import <AsyncDisplayKit/ASCenterLayoutSpec.h>
#import <AsyncDisplayKit/ASCornerLayoutSpec.h>
#import <AsyncDisplayKit/ASRelativeLayoutSpec.h>
#import <AsyncDisplayKit/ASInsetLayoutSpec.h>
#import <AsyncDisplayKit/ASOverlayLayoutSpec.h>
Expand Down
79 changes: 79 additions & 0 deletions Source/Layout/ASCornerLayoutSpec.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//
// ASCornerLayoutSpec.h
// Texture
//
// Copyright (c) 2017-present, Pinterest, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//

#import <AsyncDisplayKit/ASLayoutSpec.h>

/**
The corner location for positioning corner element.
*/
typedef NS_ENUM(NSInteger, ASCornerLayoutLocation) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coding convention: Method, @interface, and @implementation brackets on the following line.

Please also update the rest of this diff to follow the convention.

ASCornerLayoutLocationTopLeft,
ASCornerLayoutLocationTopRight,
ASCornerLayoutLocationBottomLeft,
ASCornerLayoutLocationBottomRight,
};

NS_ASSUME_NONNULL_BEGIN

/**
A layout spec that positions a corner element which relatives to the child element.

@warning Both child element and corner element must have valid preferredSize for layout calculation.
*/
@interface ASCornerLayoutSpec : ASLayoutSpec

/**
A layout spec that positions a corner element which relatives to the child element.

@param child A child that is laid out to determine the size of this spec.
@param corner A layoutElement object that is laid out to a corner on the child.
@param location The corner position option.
@return An ASCornerLayoutSpec object with a given child and an layoutElement that act as corner.
*/
- (instancetype)initWithChild:(id <ASLayoutElement>)child corner:(id <ASLayoutElement>)corner location:(ASCornerLayoutLocation)location AS_WARN_UNUSED_RESULT;

/**
A layout spec that positions a corner element which relatives to the child element.

@param child A child that is laid out to determine the size of this spec.
@param corner A layoutElement object that is laid out to a corner on the child.
@param location The corner position option.
@return An ASCornerLayoutSpec object with a given child and an layoutElement that act as corner.
*/
+ (instancetype)cornerLayoutSpecWithChild:(id <ASLayoutElement>)child corner:(id <ASLayoutElement>)corner location:(ASCornerLayoutLocation)location AS_WARN_UNUSED_RESULT;

/**
A layoutElement object that is laid out to a corner on the child.
*/
@property (nonatomic, strong) id <ASLayoutElement> corner;

/**
The corner position option.
*/
@property (nonatomic, assign) ASCornerLayoutLocation cornerLocation;

/**
The point which offsets from the corner location. Use this property to make delta
distance from the default corner location. Default is CGPointZero.
*/
@property (nonatomic, assign) CGPoint offset;

/**
Whether should include corner element into layout size calculation. If included,
the layout size will be the union size of both child and corner; If not included,
the layout size will be only child's size. Default is NO.
*/
@property (nonatomic, assign) BOOL wrapsCorner;

@end

NS_ASSUME_NONNULL_END
169 changes: 169 additions & 0 deletions Source/Layout/ASCornerLayoutSpec.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
//
// ASCornerLayoutSpec.mm
// Texture
//
// Copyright (c) 2017-present, Pinterest, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//

#import <AsyncDisplayKit/ASCornerLayoutSpec.h>
#import <AsyncDisplayKit/ASLayout.h>
#import <AsyncDisplayKit/ASLayoutSpec+Subclasses.h>
#import <AsyncDisplayKit/ASDisplayNode.h>

CGPoint as_calculatedCornerOriginIn(CGRect baseFrame, CGSize cornerSize, ASCornerLayoutLocation cornerLocation, CGPoint offset) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: open curly bracket in a new line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for refining so much details on the new layout spec. I kept the curly bracket at the end of function as the code guide line declared. 🤔🤔🤔 It says:

  • Function brackets on the same line
static void someFunction() {
  // Implementation
}


CGPoint cornerOrigin = CGPointZero;
CGPoint baseOrigin = baseFrame.origin;
CGSize baseSize = baseFrame.size;

switch (cornerLocation) {
case ASCornerLayoutLocationTopLeft:
cornerOrigin.x = baseOrigin.x - cornerSize.width / 2;
cornerOrigin.y = baseOrigin.y - cornerSize.height / 2;
break;
case ASCornerLayoutLocationTopRight:
cornerOrigin.x = baseOrigin.x + baseSize.width - cornerSize.width / 2;
cornerOrigin.y = baseOrigin.y - cornerSize.height / 2;
break;
case ASCornerLayoutLocationBottomLeft:
cornerOrigin.x = baseOrigin.x - cornerSize.width / 2;
cornerOrigin.y = baseOrigin.y + baseSize.height - cornerSize.height / 2;
break;
case ASCornerLayoutLocationBottomRight:
cornerOrigin.x = baseOrigin.x + baseSize.width - cornerSize.width / 2;
cornerOrigin.y = baseOrigin.y + baseSize.height - cornerSize.height / 2;
break;
}

cornerOrigin.x += offset.x;
cornerOrigin.y += offset.y;

return cornerOrigin;
}

static NSUInteger const kBaseChildIndex = 0;
static NSUInteger const kCornerChildIndex = 1;

@interface ASCornerLayoutSpec()
@end

@implementation ASCornerLayoutSpec

- (instancetype)initWithChild:(id <ASLayoutElement>)child corner:(id <ASLayoutElement>)corner location:(ASCornerLayoutLocation)location
{
self = [super init];
if (self) {
self.child = child;
self.corner = corner;
self.cornerLocation = location;
}
return self;
}

+ (instancetype)cornerLayoutSpecWithChild:(id <ASLayoutElement>)child corner:(id <ASLayoutElement>)corner location:(ASCornerLayoutLocation)location
{
return [[self alloc] initWithChild:child corner:corner location:location];
}

#pragma mark - Children

- (void)setChild:(id<ASLayoutElement>)child
{
ASDisplayNodeAssertNotNil(child, @"Child shouldn't be nil.");
[super setChild:child atIndex:kBaseChildIndex];
}

- (id<ASLayoutElement>)child
{
return [super childAtIndex:kBaseChildIndex];
}

- (void)setCorner:(id<ASLayoutElement>)corner
{
ASDisplayNodeAssertNotNil(corner, @"Corner element cannot be nil.");
[super setChild:corner atIndex:kCornerChildIndex];
}

- (id<ASLayoutElement>)corner
{
return [super childAtIndex:kCornerChildIndex];
}

#pragma mark - Calculation

- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole layout algorithm is a beauty!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great to hear that 😁

{
CGSize size = {
ASPointsValidForSize(constrainedSize.max.width) == NO ? ASLayoutElementParentDimensionUndefined : constrainedSize.max.width,
ASPointsValidForSize(constrainedSize.max.height) == NO ? ASLayoutElementParentDimensionUndefined : constrainedSize.max.height
};

id <ASLayoutElement> child = self.child;
id <ASLayoutElement> corner = self.corner;

// Element validation
[self _validateElement:child];
[self _validateElement:corner];

CGRect childFrame = CGRectZero;
CGRect cornerFrame = CGRectZero;

// Layout child
ASLayout *childLayout = [child layoutThatFits:constrainedSize parentSize:size];
childFrame.size = childLayout.size;

// Layout corner
ASLayout *cornerLayout = [corner layoutThatFits:constrainedSize parentSize:size];
cornerFrame.size = cornerLayout.size;

// Calculate corner's position
CGPoint relativePosition = as_calculatedCornerOriginIn(childFrame, cornerFrame.size, _cornerLocation, _offset);

// Update corner's position
cornerFrame.origin = relativePosition;

// Calculate size
CGRect frame = childFrame;
if (_wrapsCorner) {
frame = CGRectUnion(childFrame, cornerFrame);
frame.size = ASSizeRangeClamp(constrainedSize, frame.size);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, always clamp against the constrained size range 👍

}

// Shift sublayouts' positions if they are off the bounds.
if (frame.origin.x != 0) {
CGFloat deltaX = frame.origin.x;
childFrame.origin.x -= deltaX;
cornerFrame.origin.x -= deltaX;
}

if (frame.origin.y != 0) {
CGFloat deltaY = frame.origin.y;
childFrame.origin.y -= deltaY;
cornerFrame.origin.y -= deltaY;
}

childLayout.position = childFrame.origin;
cornerLayout.position = cornerFrame.origin;

return [ASLayout layoutWithLayoutElement:self size:frame.size sublayouts:@[childLayout, cornerLayout]];
}

- (void)_validateElement:(id <ASLayoutElement>)element
{
// Validate non-nil element
if (element == nil) {
ASDisplayNodeAssertNotNil(element, @"[%@]: Must have a non-nil child/corner for layout calculation.", self.class);
}
// Validate preferredSize if needed
CGSize size = element.style.preferredSize;
if (!CGSizeEqualToSize(size, CGSizeZero) && !ASIsCGSizeValidForSize(size) && (size.width < 0 || (size.height < 0))) {
ASDisplayNodeFailAssert(@"[%@]: Should give a valid preferredSize value for %@ before corner's position calculation.", self.class, element);
}
}

@end
Loading