[Layout] Add extensibility support to ASLayoutElementStyle (#2975)

* Add extensibility support to ASLayoutElementStyle

* Fix some typo
This commit is contained in:
Michael Schneider 2017-02-07 10:34:09 -08:00 committed by GitHub
parent d2da941960
commit f21254593d
3 changed files with 194 additions and 1 deletions

View File

@ -588,6 +588,7 @@
698C8B601CAB49FC0052DC3F /* ASLayoutElementExtensibility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutElementExtensibility.h; path = AsyncDisplayKit/Layout/ASLayoutElementExtensibility.h; sourceTree = "<group>"; }; 698C8B601CAB49FC0052DC3F /* ASLayoutElementExtensibility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutElementExtensibility.h; path = AsyncDisplayKit/Layout/ASLayoutElementExtensibility.h; sourceTree = "<group>"; };
698DFF431E36B6C9002891F1 /* ASStackLayoutSpecUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASStackLayoutSpecUtilities.h; sourceTree = "<group>"; }; 698DFF431E36B6C9002891F1 /* ASStackLayoutSpecUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASStackLayoutSpecUtilities.h; sourceTree = "<group>"; };
698DFF461E36B7E9002891F1 /* ASLayoutSpecUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutSpecUtilities.h; sourceTree = "<group>"; }; 698DFF461E36B7E9002891F1 /* ASLayoutSpecUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutSpecUtilities.h; sourceTree = "<group>"; };
699B83501E3C1BA500433FA4 /* ASLayoutSpecTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASLayoutSpecTests.m; sourceTree = "<group>"; };
69B225661D72535E00B25B22 /* ASDisplayNodeLayoutTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASDisplayNodeLayoutTests.mm; sourceTree = "<group>"; }; 69B225661D72535E00B25B22 /* ASDisplayNodeLayoutTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASDisplayNodeLayoutTests.mm; sourceTree = "<group>"; };
69B225681D7265DA00B25B22 /* ASXCTExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASXCTExtensions.h; sourceTree = "<group>"; }; 69B225681D7265DA00B25B22 /* ASXCTExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASXCTExtensions.h; sourceTree = "<group>"; };
69CB62A91CB8165900024920 /* _ASDisplayViewAccessiblity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ASDisplayViewAccessiblity.h; sourceTree = "<group>"; }; 69CB62A91CB8165900024920 /* _ASDisplayViewAccessiblity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ASDisplayViewAccessiblity.h; sourceTree = "<group>"; };
@ -1020,6 +1021,7 @@
2538B6F21BC5D2A2003CA0B4 /* ASCollectionViewFlowLayoutInspectorTests.m */, 2538B6F21BC5D2A2003CA0B4 /* ASCollectionViewFlowLayoutInspectorTests.m */,
69FEE53C1D95A9AF0086F066 /* ASLayoutElementStyleTests.m */, 69FEE53C1D95A9AF0086F066 /* ASLayoutElementStyleTests.m */,
695BE2541DC1245C008E6EA5 /* ASWrapperSpecSnapshotTests.mm */, 695BE2541DC1245C008E6EA5 /* ASWrapperSpecSnapshotTests.mm */,
699B83501E3C1BA500433FA4 /* ASLayoutSpecTests.m */,
); );
name = Tests; name = Tests;
path = AsyncDisplayKitTests; path = AsyncDisplayKitTests;
@ -1763,6 +1765,7 @@
CCB2F34D1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m in Sources */, CCB2F34D1D63CCC6004E6DE9 /* ASDisplayNodeSnapshotTests.m in Sources */,
AE6987C11DD04E1000B9E458 /* ASPagerNodeTests.m in Sources */, AE6987C11DD04E1000B9E458 /* ASPagerNodeTests.m in Sources */,
058D0A3A195D057000B7D73C /* ASDisplayNodeTests.m in Sources */, 058D0A3A195D057000B7D73C /* ASDisplayNodeTests.m in Sources */,
699B83511E3C1BA500433FA4 /* ASLayoutSpecTests.m in Sources */,
696FCB311D6E46050093471E /* ASBackgroundLayoutSpecSnapshotTests.mm in Sources */, 696FCB311D6E46050093471E /* ASBackgroundLayoutSpecSnapshotTests.mm in Sources */,
69FEE53D1D95A9AF0086F066 /* ASLayoutElementStyleTests.m in Sources */, 69FEE53D1D95A9AF0086F066 /* ASLayoutElementStyleTests.m in Sources */,
CC4981B31D1A02BE004E13CC /* ASTableViewThrashTests.m in Sources */, CC4981B31D1A02BE004E13CC /* ASTableViewThrashTests.m in Sources */,

View File

@ -16,6 +16,10 @@
#import <Foundation/NSGeometry.h> #import <Foundation/NSGeometry.h>
#endif #endif
#import <objc/runtime.h>
#pragma mark - ASLayoutElementExtensibility
@protocol ASLayoutElementExtensibility <NSObject> @protocol ASLayoutElementExtensibility <NSObject>
// The maximum number of extended values per type are defined in ASEnvironment.h above the ASEnvironmentStateExtensions // The maximum number of extended values per type are defined in ASEnvironment.h above the ASEnvironmentStateExtensions
@ -30,5 +34,80 @@
- (void)setLayoutOptionExtensionEdgeInsets:(UIEdgeInsets)value atIndex:(int)idx; - (void)setLayoutOptionExtensionEdgeInsets:(UIEdgeInsets)value atIndex:(int)idx;
- (UIEdgeInsets)layoutOptionExtensionEdgeInsetsAtIndex:(int)idx; - (UIEdgeInsets)layoutOptionExtensionEdgeInsetsAtIndex:(int)idx;
@end @end
#pragma mark - Dynamic Properties
/**
* Unbox NSNumber based on the type
*/
#define ASDK_UNBOX_NUMBER(NUMBER, PROPERTY_TYPE) \
const char *objCType = [NUMBER objCType]; \
if (strcmp(objCType, @encode(BOOL)) == 0) { \
return (PROPERTY_TYPE)[obj boolValue]; \
} else if (strcmp(objCType, @encode(int)) == 0) { \
return (PROPERTY_TYPE)[obj intValue]; \
} else if (strcmp(objCType, @encode(NSInteger)) == 0) { \
return (PROPERTY_TYPE)[obj integerValue]; \
} else if (strcmp(objCType, @encode(NSUInteger)) == 0) { \
return (PROPERTY_TYPE)[obj unsignedIntegerValue]; \
} else if (strcmp(objCType, @encode(CGFloat)) == 0) { \
return (PROPERTY_TYPE)[obj floatValue]; \
} else { \
NSAssert(NO, @"Data type not supported"); \
} \
/**
* Define a NSObject property
*/
#define ASDK_STYLE_PROP_OBJ(PROPERTY_TYPE, PROPERTY_NAME, SETTER_NAME) \
@dynamic PROPERTY_NAME; \
- (PROPERTY_TYPE)PROPERTY_NAME \
{ \
return (PROPERTY_TYPE)objc_getAssociatedObject(self, @selector(PROPERTY_NAME)); \
} \
\
- (void)SETTER_NAME:(PROPERTY_TYPE)PROPERTY_NAME \
{ \
objc_setAssociatedObject(self, @selector(PROPERTY_NAME), PROPERTY_NAME, OBJC_ASSOCIATION_RETAIN); \
} \
/**
* Define an primitive property
*/
#define ASDK_STYLE_PROP_PRIM(PROPERTY_TYPE, PROPERTY_NAME, SETTER_NAME, DEFAULT_VALUE) \
@dynamic PROPERTY_NAME; \
- (PROPERTY_TYPE)PROPERTY_NAME \
{ \
id obj = objc_getAssociatedObject(self, @selector(PROPERTY_NAME)); \
\
if (obj != nil) { \
ASDK_UNBOX_NUMBER(obj, PROPERTY_TYPE); \
} \
\
return DEFAULT_VALUE;\
} \
\
- (void)SETTER_NAME:(PROPERTY_TYPE)PROPERTY_NAME \
{ \
objc_setAssociatedObject(self, @selector(PROPERTY_NAME), @(PROPERTY_NAME), OBJC_ASSOCIATION_RETAIN); \
} \
/**
* Define an structure property
*/
#define ASDK_STYLE_PROP_STR(PROPERTY_TYPE, PROPERTY_NAME, SETTER_NAME, DEFAULT_STRUCT) \
@dynamic PROPERTY_NAME; \
- (PROPERTY_TYPE)PROPERTY_NAME \
{ \
id obj = objc_getAssociatedObject(self, @selector(PROPERTY_NAME)); \
if (obj == nil) { \
return DEFAULT_STRUCT; \
} \
PROPERTY_TYPE PROPERTY_NAME; [obj getValue:&PROPERTY_NAME]; return PROPERTY_NAME; \
} \
\
- (void)SETTER_NAME:(PROPERTY_TYPE)PROPERTY_NAME \
{ \
objc_setAssociatedObject(self, @selector(PROPERTY_NAME), [NSValue value:&PROPERTY_NAME withObjCType:@encode(PROPERTY_TYPE)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);\
} \

View File

@ -0,0 +1,111 @@
//
// ASLayoutSpecTests.m
// AsyncDisplayKit
//
// Created by Michael Schneider on 1/27/17.
// Copyright © 2017 Facebook. All rights reserved.
//
#import <XCTest/XCTest.h>
#import <AsyncDisplayKit/AsyncDisplayKit.h>
#import <AsyncDisplayKit/ASLayoutElementExtensibility.h>
#pragma mark - ASDKExtendedLayoutSpec
/*
* Extend the ASDKExtendedLayoutElement
* It adds a
* - primitive / CGFloat (extendedWidth)
* - struct / ASDimension (extendedDimension)
* - primitive / ASStackLayoutDirection (extendedDirection)
*/
@protocol ASDKExtendedLayoutElement <NSObject>
@property (assign, nonatomic) CGFloat extendedWidth;
@property (assign, nonatomic) ASDimension extendedDimension;
@property (copy, nonatomic) NSString *extendedName;
@end
/*
* Let the ASLayoutElementStyle conform to the ASDKExtendedLayoutElement protocol and add properties implementation
*/
@interface ASLayoutElementStyle (ASDKExtendedLayoutElement) <ASDKExtendedLayoutElement>
@end
@implementation ASLayoutElementStyle (ASDKExtendedLayoutElement)
ASDK_STYLE_PROP_PRIM(CGFloat, extendedWidth, setExtendedWidth, 0);
ASDK_STYLE_PROP_STR(ASDimension, extendedDimension, setExtendedDimension, ASDimensionMake(ASDimensionUnitAuto, 0));
ASDK_STYLE_PROP_OBJ(NSString *, extendedName, setExtendedName);
@end
/*
* As the ASLayoutableStyle conforms to the ASDKExtendedLayoutable protocol now, ASDKExtendedLayoutable properties
* can be accessed in ASDKExtendedLayoutSpec
*/
@interface ASDKExtendedLayoutSpec : ASLayoutSpec
@end
@implementation ASDKExtendedLayoutSpec
- (void)doSetSomeStyleValuesToChildren
{
for (id<ASLayoutElement> child in self.children) {
child.style.extendedWidth = 100;
child.style.extendedDimension = ASDimensionMake(100);
child.style.extendedName = @"ASDK";
}
}
- (void)doUseSomeStyleValuesFromChildren
{
for (id<ASLayoutElement> child in self.children) {
__unused CGFloat extendedWidth = child.style.extendedWidth;
__unused ASDimension extendedDimension = child.style.extendedDimension;
__unused NSString *extendedName = child.style.extendedName;
}
}
@end
#pragma mark - ASLayoutSpecTests
@interface ASLayoutSpecTests : XCTestCase
@end
@implementation ASLayoutSpecTests
- (void)testSetPrimitiveToExtendedStyle
{
ASDisplayNode *node = [[ASDisplayNode alloc] init];
node.style.extendedWidth = 100;
XCTAssert(node.style.extendedWidth == 100, @"Primitive value should be set on extended style");
}
- (void)testSetStructToExtendedStyle
{
ASDisplayNode *node = [[ASDisplayNode alloc] init];
node.style.extendedDimension = ASDimensionMake(100);
XCTAssertTrue(ASDimensionEqualToDimension(node.style.extendedDimension, ASDimensionMake(100)), @"Struct should be set on extended style");
}
- (void)testSetObjectToExtendedStyle
{
NSString *extendedName = @"ASDK";
ASDisplayNode *node = [[ASDisplayNode alloc] init];
node.style.extendedName = extendedName;
XCTAssertEqualObjects(node.style.extendedName, extendedName, @"Object should be set on extended style");
}
- (void)testUseOfExtendedStyleProperties
{
ASDKExtendedLayoutSpec *extendedLayoutSpec = [ASDKExtendedLayoutSpec new];
extendedLayoutSpec.children = @[[[ASDisplayNode alloc] init], [[ASDisplayNode alloc] init]];
XCTAssertNoThrow([extendedLayoutSpec doSetSomeStyleValuesToChildren]);
XCTAssertNoThrow([extendedLayoutSpec doUseSomeStyleValuesFromChildren]);
}
@end