[ASRelativeLayoutSpec] New core layout spec type: Relative Position, now powers Center as well.
This spec allows positioning a child at any 9-part box position (corners, edges, or center).
@ -268,6 +268,11 @@
|
||||
767E7F8E1C90191D0066C000 /* AsyncDisplayKit+Debug.m in Sources */ = {isa = PBXBuildFile; fileRef = 764D83D31C8EA515009B4FB8 /* AsyncDisplayKit+Debug.m */; };
|
||||
81EE384F1C8E94F000456208 /* ASRunLoopQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 81EE384D1C8E94F000456208 /* ASRunLoopQueue.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
81EE38501C8E94F000456208 /* ASRunLoopQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */; };
|
||||
7A06A73A1C35F08800FE8DAA /* ASRelativeLayoutSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7A06A7381C35F08800FE8DAA /* ASRelativeLayoutSpec.mm */; };
|
||||
7A06A73B1C35F08800FE8DAA /* ASRelativeLayoutSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A06A7391C35F08800FE8DAA /* ASRelativeLayoutSpec.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
7AB338661C55B3420055FDE8 /* ASRelativeLayoutSpec.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7A06A7381C35F08800FE8DAA /* ASRelativeLayoutSpec.mm */; };
|
||||
7AB338671C55B3460055FDE8 /* ASRelativeLayoutSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A06A7391C35F08800FE8DAA /* ASRelativeLayoutSpec.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
7AB338691C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7AB338681C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm */; };
|
||||
92DD2FE31BF4B97E0074C9DD /* ASMapNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
92DD2FE41BF4B97E0074C9DD /* ASMapNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92DD2FE21BF4B97E0074C9DD /* ASMapNode.mm */; };
|
||||
92DD2FE61BF4D05E0074C9DD /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92DD2FE51BF4D05E0074C9DD /* MapKit.framework */; };
|
||||
@ -739,6 +744,9 @@
|
||||
764D83D31C8EA515009B4FB8 /* AsyncDisplayKit+Debug.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "AsyncDisplayKit+Debug.m"; sourceTree = "<group>"; };
|
||||
81EE384D1C8E94F000456208 /* ASRunLoopQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASRunLoopQueue.h; path = ../ASRunLoopQueue.h; sourceTree = "<group>"; };
|
||||
81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASRunLoopQueue.mm; path = ../ASRunLoopQueue.mm; sourceTree = "<group>"; };
|
||||
7A06A7381C35F08800FE8DAA /* ASRelativeLayoutSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASRelativeLayoutSpec.mm; path = AsyncDisplayKit/Layout/ASRelativeLayoutSpec.mm; sourceTree = "<group>"; };
|
||||
7A06A7391C35F08800FE8DAA /* ASRelativeLayoutSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASRelativeLayoutSpec.h; path = AsyncDisplayKit/Layout/ASRelativeLayoutSpec.h; sourceTree = "<group>"; };
|
||||
7AB338681C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASRelativeLayoutSpecSnapshotTests.mm; sourceTree = "<group>"; };
|
||||
92DD2FE11BF4B97E0074C9DD /* ASMapNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASMapNode.h; sourceTree = "<group>"; };
|
||||
92DD2FE21BF4B97E0074C9DD /* ASMapNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASMapNode.mm; sourceTree = "<group>"; };
|
||||
92DD2FE51BF4D05E0074C9DD /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; };
|
||||
@ -1057,6 +1065,7 @@
|
||||
05EA6FE61AC0966E00E35788 /* ASSnapshotTestCase.mm */,
|
||||
056D21541ABCEF50001107EF /* ASImageNodeSnapshotTests.m */,
|
||||
ACF6ED531B178DC700DA7C62 /* ASCenterLayoutSpecSnapshotTests.mm */,
|
||||
7AB338681C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm */,
|
||||
ACF6ED551B178DC700DA7C62 /* ASInsetLayoutSpecSnapshotTests.mm */,
|
||||
ACF6ED591B178DC700DA7C62 /* ASOverlayLayoutSpecSnapshotTests.mm */,
|
||||
ACF6ED5A1B178DC700DA7C62 /* ASRatioLayoutSpecSnapshotTests.mm */,
|
||||
@ -1316,6 +1325,8 @@
|
||||
ACF6ED131B17843500DA7C62 /* ASOverlayLayoutSpec.mm */,
|
||||
ACF6ED141B17843500DA7C62 /* ASRatioLayoutSpec.h */,
|
||||
ACF6ED151B17843500DA7C62 /* ASRatioLayoutSpec.mm */,
|
||||
7A06A7391C35F08800FE8DAA /* ASRelativeLayoutSpec.h */,
|
||||
7A06A7381C35F08800FE8DAA /* ASRelativeLayoutSpec.mm */,
|
||||
9C49C36E1B853957000B0DD5 /* ASStackLayoutable.h */,
|
||||
AC21EC0F1B3D0BF600C8B19A /* ASStackLayoutDefines.h */,
|
||||
ACF6ED161B17843500DA7C62 /* ASStackLayoutSpec.h */,
|
||||
@ -1377,6 +1388,7 @@
|
||||
058D0A6B195D05EC00B7D73C /* _ASAsyncTransactionContainer.h in Headers */,
|
||||
058D0A6D195D05EC00B7D73C /* _ASAsyncTransactionGroup.h in Headers */,
|
||||
058D0A72195D05F800B7D73C /* _ASCoreAnimationExtras.h in Headers */,
|
||||
7A06A73B1C35F08800FE8DAA /* ASRelativeLayoutSpec.h in Headers */,
|
||||
058D0A53195D05DC00B7D73C /* _ASDisplayLayer.h in Headers */,
|
||||
058D0A55195D05DC00B7D73C /* _ASDisplayView.h in Headers */,
|
||||
B13CA0F71C519E9400E031AB /* ASCollectionViewLayoutFacilitatorProtocol.h in Headers */,
|
||||
@ -1570,6 +1582,7 @@
|
||||
AC7A2C181BDE11DF0093FE1A /* ASTableViewInternal.h in Headers */,
|
||||
B35062531B010EFD0018CF92 /* ASImageNode+CGExtras.h in Headers */,
|
||||
254C6B7F1BF94DF4003EC431 /* ASTextKitTruncating.h in Headers */,
|
||||
7AB338671C55B3460055FDE8 /* ASRelativeLayoutSpec.h in Headers */,
|
||||
B35062021B010EFD0018CF92 /* ASImageNode.h in Headers */,
|
||||
B350621F1B010EFD0018CF92 /* ASImageProtocols.h in Headers */,
|
||||
430E7C901B4C23F100697A4C /* ASIndexPath.h in Headers */,
|
||||
@ -1912,6 +1925,7 @@
|
||||
CC3B20851C3F76D600798563 /* ASPendingStateController.mm in Sources */,
|
||||
ACF6ED2C1B17843500DA7C62 /* ASOverlayLayoutSpec.mm in Sources */,
|
||||
0442850F1BAA64EC00D16268 /* ASMultidimensionalArrayUtils.mm in Sources */,
|
||||
7A06A73A1C35F08800FE8DAA /* ASRelativeLayoutSpec.mm in Sources */,
|
||||
257754921BED28F300737CA5 /* ASEqualityHashHelpers.mm in Sources */,
|
||||
E52405B31C8FEF03004DC8E7 /* ASDisplayNodeLayoutContext.mm in Sources */,
|
||||
257754AB1BEE44CD00737CA5 /* ASTextKitEntityAttribute.m in Sources */,
|
||||
@ -1975,6 +1989,7 @@
|
||||
058D0A3C195D057000B7D73C /* ASMutableAttributedStringBuilderTests.m in Sources */,
|
||||
ACF6ED611B178DC700DA7C62 /* ASOverlayLayoutSpecSnapshotTests.mm in Sources */,
|
||||
ACF6ED621B178DC700DA7C62 /* ASRatioLayoutSpecSnapshotTests.mm in Sources */,
|
||||
7AB338691C55B97B0055FDE8 /* ASRelativeLayoutSpecSnapshotTests.mm in Sources */,
|
||||
254C6B541BF8FF2A003EC431 /* ASTextKitTests.mm in Sources */,
|
||||
05EA6FE71AC0966E00E35788 /* ASSnapshotTestCase.mm in Sources */,
|
||||
ACF6ED631B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm in Sources */,
|
||||
@ -2075,6 +2090,8 @@
|
||||
9C8221981BA237B80037F19A /* ASStackBaselinePositionedLayout.mm in Sources */,
|
||||
34EFC7721B701D0300AD841F /* ASStackLayoutSpec.mm in Sources */,
|
||||
34EFC7761B701D2A00AD841F /* ASStackPositionedLayout.mm in Sources */,
|
||||
DECC2ED01C35C1C600388446 /* ASRangeControllerBeta.mm in Sources */,
|
||||
7AB338661C55B3420055FDE8 /* ASRelativeLayoutSpec.mm in Sources */,
|
||||
34EFC7781B701D3100AD841F /* ASStackUnpositionedLayout.mm in Sources */,
|
||||
DE84918E1C8FFF9F003D89E9 /* ASRunLoopQueue.mm in Sources */,
|
||||
AC026B6C1BD57D6F00BBC17E /* ASChangeSetDataController.m in Sources */,
|
||||
|
||||
@ -45,6 +45,7 @@
|
||||
#import <AsyncDisplayKit/ASLayoutSpec.h>
|
||||
#import <AsyncDisplayKit/ASBackgroundLayoutSpec.h>
|
||||
#import <AsyncDisplayKit/ASCenterLayoutSpec.h>
|
||||
#import <AsyncDisplayKit/ASRelativeLayoutSpec.h>
|
||||
#import <AsyncDisplayKit/ASInsetLayoutSpec.h>
|
||||
#import <AsyncDisplayKit/ASOverlayLayoutSpec.h>
|
||||
#import <AsyncDisplayKit/ASRatioLayoutSpec.h>
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#import <AsyncDisplayKit/ASLayoutSpec.h>
|
||||
#import <AsyncDisplayKit/ASRelativeLayoutSpec.h>
|
||||
|
||||
/** How the child is centered within the spec. */
|
||||
typedef NS_OPTIONS(NSUInteger, ASCenterLayoutSpecCenteringOptions) {
|
||||
@ -25,19 +25,22 @@ typedef NS_OPTIONS(NSUInteger, ASCenterLayoutSpecCenteringOptions) {
|
||||
/** How much space the spec will take up. */
|
||||
typedef NS_OPTIONS(NSUInteger, ASCenterLayoutSpecSizingOptions) {
|
||||
/** The spec will take up the maximum size possible */
|
||||
ASCenterLayoutSpecSizingOptionDefault,
|
||||
ASCenterLayoutSpecSizingOptionDefault = ASRelativeLayoutSpecSizingOptionDefault,
|
||||
/** The spec will take up the minimum size possible along the X axis */
|
||||
ASCenterLayoutSpecSizingOptionMinimumX = 1 << 0,
|
||||
ASCenterLayoutSpecSizingOptionMinimumX = ASRelativeLayoutSpecSizingOptionMinimumWidth,
|
||||
/** The spec will take up the minimum size possible along the Y axis */
|
||||
ASCenterLayoutSpecSizingOptionMinimumY = 1 << 1,
|
||||
ASCenterLayoutSpecSizingOptionMinimumY = ASRelativeLayoutSpecSizingOptionMinimumHeight,
|
||||
/** Convenience option to take up the minimum size along both the X and Y axis */
|
||||
ASCenterLayoutSpecSizingOptionMinimumXY = ASCenterLayoutSpecSizingOptionMinimumX | ASCenterLayoutSpecSizingOptionMinimumY,
|
||||
ASCenterLayoutSpecSizingOptionMinimumXY = ASRelativeLayoutSpecSizingOptionMinimumSize
|
||||
};
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/** Lays out a single layoutable child and position it so that it is centered into the layout bounds. */
|
||||
@interface ASCenterLayoutSpec : ASLayoutSpec
|
||||
/** Lays out a single layoutable child and position it so that it is centered into the layout bounds.
|
||||
* NOTE: ASRelativeLayoutSpec offers all of the capabilities of Center, and more.
|
||||
* Check it out if you would like to be able to position the child at any corner or the middle of an edge.
|
||||
*/
|
||||
@interface ASCenterLayoutSpec : ASRelativeLayoutSpec
|
||||
|
||||
@property (nonatomic, assign) ASCenterLayoutSpecCenteringOptions centeringOptions;
|
||||
@property (nonatomic, assign) ASCenterLayoutSpecSizingOptions sizingOptions;
|
||||
|
||||
@ -23,13 +23,14 @@
|
||||
sizingOptions:(ASCenterLayoutSpecSizingOptions)sizingOptions
|
||||
child:(id<ASLayoutable>)child;
|
||||
{
|
||||
if (!(self = [super init])) {
|
||||
ASRelativeLayoutSpecPosition verticalPosition = [self verticalPositionFromCenteringOptions:centeringOptions];
|
||||
ASRelativeLayoutSpecPosition horizontalPosition = [self horizontalPositionFromCenteringOptions:centeringOptions];
|
||||
|
||||
if (!(self = [super initWithHorizontalPosition:horizontalPosition verticalPosition:verticalPosition sizingOption:sizingOptions child:child])) {
|
||||
return nil;
|
||||
}
|
||||
ASDisplayNodeAssertNotNil(child, @"Child cannot be nil");
|
||||
_centeringOptions = centeringOptions;
|
||||
_sizingOptions = sizingOptions;
|
||||
[self setChild:child];
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -44,61 +45,36 @@
|
||||
{
|
||||
ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable");
|
||||
_centeringOptions = centeringOptions;
|
||||
|
||||
[self setHorizontalPosition:[self horizontalPositionFromCenteringOptions:centeringOptions]];
|
||||
[self setVerticalPosition:[self verticalPositionFromCenteringOptions:centeringOptions]];
|
||||
}
|
||||
|
||||
- (void)setSizingOptions:(ASCenterLayoutSpecSizingOptions)sizingOptions
|
||||
{
|
||||
ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable");
|
||||
_sizingOptions = sizingOptions;
|
||||
[self setSizingOption:sizingOptions];
|
||||
}
|
||||
|
||||
- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize
|
||||
- (ASRelativeLayoutSpecPosition)horizontalPositionFromCenteringOptions:(ASCenterLayoutSpecCenteringOptions)centeringOptions
|
||||
{
|
||||
CGSize size = {
|
||||
constrainedSize.max.width,
|
||||
constrainedSize.max.height
|
||||
};
|
||||
|
||||
// Layout the child
|
||||
const CGSize minChildSize = {
|
||||
(_centeringOptions & ASCenterLayoutSpecCenteringX) != 0 ? 0 : constrainedSize.min.width,
|
||||
(_centeringOptions & ASCenterLayoutSpecCenteringY) != 0 ? 0 : constrainedSize.min.height,
|
||||
};
|
||||
ASLayout *sublayout = [self.child measureWithSizeRange:ASSizeRangeMake(minChildSize, constrainedSize.max)];
|
||||
|
||||
// If we have an undetermined height or width, use the child size to define the layout
|
||||
// size
|
||||
size = ASSizeRangeClamp(constrainedSize, {
|
||||
isnan(size.width) ? sublayout.size.width : size.width,
|
||||
isnan(size.height) ? sublayout.size.height : size.height
|
||||
});
|
||||
|
||||
// If minimum size options are set, attempt to shrink the size to the size of the child
|
||||
size = ASSizeRangeClamp(constrainedSize, {
|
||||
MIN(size.width, (_sizingOptions & ASCenterLayoutSpecSizingOptionMinimumX) != 0 ? sublayout.size.width : size.width),
|
||||
MIN(size.height, (_sizingOptions & ASCenterLayoutSpecSizingOptionMinimumY) != 0 ? sublayout.size.height : size.height)
|
||||
});
|
||||
|
||||
// Compute the centered position for the child
|
||||
BOOL shouldCenterAlongX = (_centeringOptions & ASCenterLayoutSpecCenteringX);
|
||||
BOOL shouldCenterAlongY = (_centeringOptions & ASCenterLayoutSpecCenteringY);
|
||||
sublayout.position = {
|
||||
ASRoundPixelValue(shouldCenterAlongX ? (size.width - sublayout.size.width) * 0.5f : 0),
|
||||
ASRoundPixelValue(shouldCenterAlongY ? (size.height - sublayout.size.height) * 0.5f : 0)
|
||||
};
|
||||
|
||||
return [ASLayout layoutWithLayoutableObject:self size:size sublayouts:@[sublayout]];
|
||||
BOOL centerX = (centeringOptions & ASCenterLayoutSpecCenteringX) != 0;
|
||||
if (centerX) {
|
||||
return ASRelativeLayoutSpecPositionCenter;
|
||||
} else {
|
||||
return ASRelativeLayoutSpecPositionStart;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setChildren:(NSArray *)children
|
||||
- (ASRelativeLayoutSpecPosition)verticalPositionFromCenteringOptions:(ASCenterLayoutSpecCenteringOptions)centeringOptions
|
||||
{
|
||||
ASDisplayNodeAssert(NO, @"not supported by this layout spec");
|
||||
}
|
||||
|
||||
- (NSArray *)children
|
||||
{
|
||||
ASDisplayNodeAssert(NO, @"not supported by this layout spec");
|
||||
return nil;
|
||||
BOOL centerY = (centeringOptions & ASCenterLayoutSpecCenteringY) != 0;
|
||||
if (centerY) {
|
||||
return ASRelativeLayoutSpecPositionCenter;
|
||||
} else {
|
||||
return ASRelativeLayoutSpecPositionStart;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
73
AsyncDisplayKit/Layout/ASRelativeLayoutSpec.h
Normal file
@ -0,0 +1,73 @@
|
||||
//
|
||||
// ASRelativeLayoutSpec.h
|
||||
// AsyncDisplayKit
|
||||
//
|
||||
// Created by Samuel Stow on 12/31/15.
|
||||
//
|
||||
|
||||
#import <AsyncDisplayKit/ASLayoutSpec.h>
|
||||
|
||||
/** How the child is positioned within the spec. */
|
||||
typedef NS_OPTIONS(NSUInteger, ASRelativeLayoutSpecPosition) {
|
||||
/** The child is positioned at point 0 relatively to the layout axis (ie left / top most) */
|
||||
ASRelativeLayoutSpecPositionStart = 0,
|
||||
/** The child is centered along the specified axis */
|
||||
ASRelativeLayoutSpecPositionCenter = 1 << 0,
|
||||
/** The child is positioned at the maximum point of the layout axis (ie right / bottom most) */
|
||||
ASRelativeLayoutSpecPositionEnd = 1 << 1,
|
||||
};
|
||||
|
||||
/** How much space the spec will take up. */
|
||||
typedef NS_OPTIONS(NSUInteger, ASRelativeLayoutSpecSizingOption) {
|
||||
/** The spec will take up the maximum size possible */
|
||||
ASRelativeLayoutSpecSizingOptionDefault,
|
||||
/** The spec will take up the minimum size possible along the X axis */
|
||||
ASRelativeLayoutSpecSizingOptionMinimumWidth = 1 << 0,
|
||||
/** The spec will take up the minimum size possible along the Y axis */
|
||||
ASRelativeLayoutSpecSizingOptionMinimumHeight = 1 << 1,
|
||||
/** Convenience option to take up the minimum size along both the X and Y axis */
|
||||
ASRelativeLayoutSpecSizingOptionMinimumSize = ASRelativeLayoutSpecSizingOptionMinimumWidth | ASRelativeLayoutSpecSizingOptionMinimumHeight,
|
||||
};
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/** Lays out a single layoutable child and positions it within the layout bounds according to vertical and horizontal positional specifiers.
|
||||
* Can position the child at any of the 4 corners, or the middle of any of the 4 edges, as well as the center - similar to "9-part" image areas.
|
||||
*/
|
||||
@interface ASRelativeLayoutSpec : ASLayoutSpec
|
||||
|
||||
// You may create a spec with alloc / init, then set any non-default properties; or use a convenience initialize that accepts all properties.
|
||||
@property (nonatomic, assign) ASRelativeLayoutSpecPosition horizontalPosition;
|
||||
@property (nonatomic, assign) ASRelativeLayoutSpecPosition verticalPosition;
|
||||
@property (nonatomic, assign) ASRelativeLayoutSpecSizingOption sizingOption;
|
||||
|
||||
/*!
|
||||
* @discussion convenience constructor for a ASRelativeLayoutSpec
|
||||
* @param horizontalPosition how to position the item on the horizontal (x) axis
|
||||
* @param verticalPosition how to position the item on the vertical (y) axis
|
||||
* @param sizingOption how much size to take up
|
||||
* @param child the child to layout
|
||||
* @return a configured ASRelativeLayoutSpec
|
||||
*/
|
||||
+ (instancetype)relativePositionLayoutSpecWithHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition
|
||||
verticalPosition:(ASRelativeLayoutSpecPosition)verticalPosition
|
||||
sizingOption:(ASRelativeLayoutSpecSizingOption)sizingOption
|
||||
child:(id<ASLayoutable>)child;
|
||||
|
||||
/*!
|
||||
* @discussion convenience initializer for a ASRelativeLayoutSpec
|
||||
* @param horizontalPosition how to position the item on the horizontal (x) axis
|
||||
* @param verticalPosition how to position the item on the vertical (y) axis
|
||||
* @param sizingOption how much size to take up
|
||||
* @param child the child to layout
|
||||
* @return a configured ASRelativeLayoutSpec
|
||||
*/
|
||||
- (instancetype)initWithHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition
|
||||
verticalPosition:(ASRelativeLayoutSpecPosition)verticalPosition
|
||||
sizingOption:(ASRelativeLayoutSpecSizingOption)sizingOption
|
||||
child:(id<ASLayoutable>)child;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
117
AsyncDisplayKit/Layout/ASRelativeLayoutSpec.mm
Normal file
@ -0,0 +1,117 @@
|
||||
//
|
||||
// ASRelativeLayoutSpec.mm
|
||||
// AsyncDisplayKit
|
||||
//
|
||||
// Created by Samuel Stow on 12/31/15.
|
||||
//
|
||||
|
||||
#import "ASRelativeLayoutSpec.h"
|
||||
|
||||
#import "ASInternalHelpers.h"
|
||||
#import "ASLayout.h"
|
||||
|
||||
@implementation ASRelativeLayoutSpec
|
||||
|
||||
- (instancetype)initWithHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition verticalPosition:(ASRelativeLayoutSpecPosition)verticalPosition sizingOption:(ASRelativeLayoutSpecSizingOption)sizingOption child:(id<ASLayoutable>)child
|
||||
{
|
||||
if (!(self = [super init])) {
|
||||
return nil;
|
||||
}
|
||||
ASDisplayNodeAssertNotNil(child, @"Child cannot be nil");
|
||||
_horizontalPosition = horizontalPosition;
|
||||
_verticalPosition = verticalPosition;
|
||||
_sizingOption = sizingOption;
|
||||
[self setChild:child];
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)relativePositionLayoutSpecWithHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition verticalPosition:(ASRelativeLayoutSpecPosition)verticalPosition sizingOption:(ASRelativeLayoutSpecSizingOption)sizingOption child:(id<ASLayoutable>)child
|
||||
{
|
||||
return [[self alloc] initWithHorizontalPosition:horizontalPosition verticalPosition:verticalPosition sizingOption:sizingOption child:child];
|
||||
}
|
||||
|
||||
- (void)setHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition
|
||||
{
|
||||
ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable");
|
||||
_horizontalPosition = horizontalPosition;
|
||||
}
|
||||
|
||||
- (void)setVerticalPosition:(ASRelativeLayoutSpecPosition)verticalPosition {
|
||||
ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable");
|
||||
_verticalPosition = verticalPosition;
|
||||
}
|
||||
|
||||
- (void)setSizingOption:(ASRelativeLayoutSpecSizingOption)sizingOption
|
||||
{
|
||||
ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable");
|
||||
_sizingOption = sizingOption;
|
||||
}
|
||||
|
||||
- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize
|
||||
{
|
||||
CGSize size = {
|
||||
constrainedSize.max.width,
|
||||
constrainedSize.max.height
|
||||
};
|
||||
|
||||
BOOL reduceWidth = (_horizontalPosition & ASRelativeLayoutSpecPositionCenter) != 0 ||
|
||||
(_horizontalPosition & ASRelativeLayoutSpecPositionEnd) != 0;
|
||||
|
||||
BOOL reduceHeight = (_verticalPosition & ASRelativeLayoutSpecPositionCenter) != 0 ||
|
||||
(_verticalPosition & ASRelativeLayoutSpecPositionEnd) != 0;
|
||||
|
||||
// Layout the child
|
||||
const CGSize minChildSize = {
|
||||
reduceWidth ? 0 : constrainedSize.min.width,
|
||||
reduceHeight ? 0 : constrainedSize.min.height,
|
||||
};
|
||||
ASLayout *sublayout = [self.child measureWithSizeRange:ASSizeRangeMake(minChildSize, constrainedSize.max)];
|
||||
|
||||
// If we have an undetermined height or width, use the child size to define the layout
|
||||
// size
|
||||
size = ASSizeRangeClamp(constrainedSize, {
|
||||
isfinite(size.width) == NO ? sublayout.size.width : size.width,
|
||||
isfinite(size.height) == NO ? sublayout.size.height : size.height
|
||||
});
|
||||
|
||||
// If minimum size options are set, attempt to shrink the size to the size of the child
|
||||
size = ASSizeRangeClamp(constrainedSize, {
|
||||
MIN(size.width, (_sizingOption & ASRelativeLayoutSpecSizingOptionMinimumWidth) != 0 ? sublayout.size.width : size.width),
|
||||
MIN(size.height, (_sizingOption & ASRelativeLayoutSpecSizingOptionMinimumHeight) != 0 ? sublayout.size.height : size.height)
|
||||
});
|
||||
|
||||
// Compute the position for the child on each axis according to layout parameters
|
||||
CGFloat xPosition = [self proportionOfAxisForAxisPosition:_horizontalPosition];
|
||||
CGFloat yPosition = [self proportionOfAxisForAxisPosition:_verticalPosition];
|
||||
|
||||
sublayout.position = {
|
||||
ASRoundPixelValue((size.width - sublayout.size.width) * xPosition),
|
||||
ASRoundPixelValue((size.height - sublayout.size.height) * yPosition)
|
||||
};
|
||||
|
||||
return [ASLayout layoutWithLayoutableObject:self size:size sublayouts:@[sublayout]];
|
||||
}
|
||||
|
||||
- (void)setChildren:(NSArray *)children
|
||||
{
|
||||
ASDisplayNodeAssert(NO, @"not supported by this layout spec");
|
||||
}
|
||||
|
||||
- (NSArray *)children
|
||||
{
|
||||
ASDisplayNodeAssert(NO, @"not supported by this layout spec");
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CGFloat)proportionOfAxisForAxisPosition:(ASRelativeLayoutSpecPosition)position
|
||||
{
|
||||
if ((position & ASRelativeLayoutSpecPositionCenter) != 0) {
|
||||
return 0.5f;
|
||||
} else if ((position & ASRelativeLayoutSpecPositionEnd) != 0) {
|
||||
return 1.0f;
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@ -38,10 +38,14 @@ static const ASSizeRange kSize = {{100, 120}, {320, 160}};
|
||||
|
||||
- (void)testWithSizingOptions
|
||||
{
|
||||
[self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone sizingOptions:ASCenterLayoutSpecSizingOptionDefault];
|
||||
[self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone sizingOptions:ASCenterLayoutSpecSizingOptionMinimumX];
|
||||
[self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone sizingOptions:ASCenterLayoutSpecSizingOptionMinimumY];
|
||||
[self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone sizingOptions:ASCenterLayoutSpecSizingOptionMinimumXY];
|
||||
[self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone
|
||||
sizingOptions:ASCenterLayoutSpecSizingOptionDefault];
|
||||
[self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone
|
||||
sizingOptions:ASCenterLayoutSpecSizingOptionMinimumX];
|
||||
[self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone
|
||||
sizingOptions:ASCenterLayoutSpecSizingOptionMinimumY];
|
||||
[self testWithCenteringOptions:ASCenterLayoutSpecCenteringNone
|
||||
sizingOptions:ASCenterLayoutSpecSizingOptionMinimumXY];
|
||||
}
|
||||
|
||||
- (void)testWithCenteringOptions:(ASCenterLayoutSpecCenteringOptions)options
|
||||
@ -51,14 +55,7 @@ static const ASSizeRange kSize = {{100, 120}, {320, 160}};
|
||||
ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor]);
|
||||
foregroundNode.staticSize = {70, 100};
|
||||
|
||||
ASLayoutSpec *layoutSpec =
|
||||
[ASBackgroundLayoutSpec
|
||||
backgroundLayoutSpecWithChild:
|
||||
[ASCenterLayoutSpec
|
||||
centerLayoutSpecWithCenteringOptions:options
|
||||
sizingOptions:sizingOptions
|
||||
child:foregroundNode]
|
||||
background:backgroundNode];
|
||||
ASLayoutSpec *layoutSpec = [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:[ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:options sizingOptions:sizingOptions child:foregroundNode]background:backgroundNode];
|
||||
|
||||
[self testLayoutSpec:layoutSpec
|
||||
sizeRange:kSize
|
||||
@ -97,14 +94,7 @@ static NSString *suffixForCenteringOptions(ASCenterLayoutSpecCenteringOptions ce
|
||||
foregroundNode.staticSize = {10, 10};
|
||||
foregroundNode.flexGrow = YES;
|
||||
|
||||
ASCenterLayoutSpec *layoutSpec =
|
||||
[ASCenterLayoutSpec
|
||||
centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringNone
|
||||
sizingOptions:{}
|
||||
child:
|
||||
[ASBackgroundLayoutSpec
|
||||
backgroundLayoutSpecWithChild:[ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical spacing:0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsStart children:@[foregroundNode]]
|
||||
background:backgroundNode]];
|
||||
ASCenterLayoutSpec *layoutSpec = [ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringNone sizingOptions:{} child:[ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:[ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical spacing:0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsStart children:@[foregroundNode]] background:backgroundNode]];
|
||||
|
||||
[self testLayoutSpec:layoutSpec sizeRange:kSize subnodes:@[backgroundNode, foregroundNode] identifier:nil];
|
||||
}
|
||||
|
||||
130
AsyncDisplayKitTests/ASRelativeLayoutSpecSnapshotTests.mm
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#import "ASLayoutSpecSnapshotTestsHelper.h"
|
||||
|
||||
#import "ASBackgroundLayoutSpec.h"
|
||||
#import "ASRelativeLayoutSpec.h"
|
||||
#import "ASStackLayoutSpec.h"
|
||||
#import "ASLayoutOptions.h"
|
||||
|
||||
static const ASSizeRange kSize = {{100, 120}, {320, 160}};
|
||||
|
||||
@interface ASRelativeLayoutSpecSnapshotTests : ASLayoutSpecSnapshotTestCase
|
||||
@end
|
||||
|
||||
@implementation ASRelativeLayoutSpecSnapshotTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
self.recordMode = NO;
|
||||
}
|
||||
|
||||
- (void)testWithOptions
|
||||
{
|
||||
|
||||
[self testAllVerticalPositionsForHorizontalPosition:ASRelativeLayoutSpecPositionStart];
|
||||
[self testAllVerticalPositionsForHorizontalPosition:ASRelativeLayoutSpecPositionCenter];
|
||||
[self testAllVerticalPositionsForHorizontalPosition:ASRelativeLayoutSpecPositionEnd];
|
||||
|
||||
}
|
||||
|
||||
- (void)testAllVerticalPositionsForHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition {
|
||||
[self testWithHorizontalPosition:horizontalPosition verticalPosition:ASRelativeLayoutSpecPositionStart sizingOptions:{}];
|
||||
[self testWithHorizontalPosition:horizontalPosition verticalPosition:ASRelativeLayoutSpecPositionCenter sizingOptions:{}];
|
||||
[self testWithHorizontalPosition:horizontalPosition verticalPosition:ASRelativeLayoutSpecPositionEnd sizingOptions:{}];
|
||||
}
|
||||
|
||||
- (void)testWithSizingOptions
|
||||
{
|
||||
[self testWithHorizontalPosition:ASRelativeLayoutSpecPositionStart
|
||||
verticalPosition:ASRelativeLayoutSpecPositionStart
|
||||
sizingOptions:ASRelativeLayoutSpecSizingOptionDefault];
|
||||
[self testWithHorizontalPosition:ASRelativeLayoutSpecPositionStart
|
||||
verticalPosition:ASRelativeLayoutSpecPositionStart
|
||||
sizingOptions:ASRelativeLayoutSpecSizingOptionMinimumWidth];
|
||||
[self testWithHorizontalPosition:ASRelativeLayoutSpecPositionStart
|
||||
verticalPosition:ASRelativeLayoutSpecPositionStart
|
||||
sizingOptions:ASRelativeLayoutSpecSizingOptionMinimumHeight];
|
||||
[self testWithHorizontalPosition:ASRelativeLayoutSpecPositionStart
|
||||
verticalPosition:ASRelativeLayoutSpecPositionStart
|
||||
sizingOptions:ASRelativeLayoutSpecSizingOptionMinimumSize];
|
||||
}
|
||||
|
||||
- (void)testWithHorizontalPosition:(ASRelativeLayoutSpecPosition)horizontalPosition
|
||||
verticalPosition:(ASRelativeLayoutSpecPosition)verticalPosition
|
||||
sizingOptions:(ASRelativeLayoutSpecSizingOption)sizingOptions
|
||||
{
|
||||
ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]);
|
||||
ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor]);
|
||||
foregroundNode.staticSize = {70, 100};
|
||||
|
||||
ASLayoutSpec *layoutSpec =
|
||||
[ASBackgroundLayoutSpec
|
||||
backgroundLayoutSpecWithChild:
|
||||
[ASRelativeLayoutSpec
|
||||
relativePositionLayoutSpecWithHorizontalPosition:horizontalPosition verticalPosition:verticalPosition sizingOption:sizingOptions child:foregroundNode]
|
||||
background:backgroundNode];
|
||||
|
||||
[self testLayoutSpec:layoutSpec
|
||||
sizeRange:kSize
|
||||
subnodes:@[backgroundNode, foregroundNode]
|
||||
identifier:suffixForPositionOptions(horizontalPosition, verticalPosition, sizingOptions)];
|
||||
}
|
||||
|
||||
static NSString *suffixForPositionOptions(ASRelativeLayoutSpecPosition horizontalPosition,
|
||||
ASRelativeLayoutSpecPosition verticalPosition,
|
||||
ASRelativeLayoutSpecSizingOption sizingOptions)
|
||||
{
|
||||
NSMutableString *suffix = [NSMutableString string];
|
||||
|
||||
if ((horizontalPosition & ASRelativeLayoutSpecPositionCenter) != 0) {
|
||||
[suffix appendString:@"CenterX"];
|
||||
} else if ((horizontalPosition & ASRelativeLayoutSpecPositionEnd) != 0) {
|
||||
[suffix appendString:@"EndX"];
|
||||
}
|
||||
|
||||
if ((verticalPosition & ASRelativeLayoutSpecPositionCenter) != 0) {
|
||||
[suffix appendString:@"CenterY"];
|
||||
} else if ((verticalPosition & ASRelativeLayoutSpecPositionEnd) != 0) {
|
||||
[suffix appendString:@"EndY"];
|
||||
}
|
||||
|
||||
if ((sizingOptions & ASRelativeLayoutSpecSizingOptionMinimumWidth) != 0) {
|
||||
[suffix appendString:@"SizingMinimumWidth"];
|
||||
}
|
||||
|
||||
if ((sizingOptions & ASRelativeLayoutSpecSizingOptionMinimumHeight) != 0) {
|
||||
[suffix appendString:@"SizingMinimumHeight"];
|
||||
}
|
||||
|
||||
return suffix;
|
||||
}
|
||||
|
||||
- (void)testMinimumSizeRangeIsGivenToChildWhenNotPositioning
|
||||
{
|
||||
ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]);
|
||||
ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]);
|
||||
foregroundNode.staticSize = {10, 10};
|
||||
foregroundNode.flexGrow = YES;
|
||||
|
||||
ASLayoutSpec *childSpec = [ASBackgroundLayoutSpec
|
||||
backgroundLayoutSpecWithChild:[ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical spacing:0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsStart children:@[foregroundNode]]
|
||||
background:backgroundNode];
|
||||
|
||||
ASRelativeLayoutSpec *layoutSpec = [ASRelativeLayoutSpec
|
||||
relativePositionLayoutSpecWithHorizontalPosition:ASRelativeLayoutSpecPositionStart verticalPosition:ASRelativeLayoutSpecPositionStart sizingOption:{} child:childSpec];
|
||||
|
||||
|
||||
[self testLayoutSpec:layoutSpec sizeRange:kSize subnodes:@[backgroundNode, foregroundNode] identifier:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 2.6 KiB |