mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Add a block API to provide an ASLayoutSpec without having to subclass ASDisplayNode
This commit is contained in:
@@ -143,6 +143,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
* encouraged.
|
||||
*
|
||||
* @note This method should not be called directly outside of ASDisplayNode; use -measure: or -calculatedLayout instead.
|
||||
*
|
||||
* @warning Overwriting layoutSpecThatFits: in a subclass and providing a layoutSpecBlock block is currently not supported
|
||||
*/
|
||||
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize;
|
||||
|
||||
|
||||
@@ -42,6 +42,11 @@ typedef void (^ASDisplayNodeDidLoadBlock)(ASDisplayNode * _Nonnull node);
|
||||
*/
|
||||
typedef void (^ASDisplayNodeContextModifier)(_Nonnull CGContextRef context);
|
||||
|
||||
/**
|
||||
* ASDisplayNode layout spec block. This block can be used instead of implementing layoutSpecThatFits: in subclass
|
||||
*/
|
||||
typedef ASLayoutSpec * _Nonnull(^ASLayoutSpecBlock)(ASSizeRange constrainedSize);
|
||||
|
||||
/**
|
||||
Interface state is available on ASDisplayNode and ASViewController, and
|
||||
allows checking whether a node is in an interface situation where it is prudent to trigger certain
|
||||
@@ -252,6 +257,17 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize;
|
||||
|
||||
|
||||
/**
|
||||
* @abstract Provides a way to declare a block to provide an ASLayoutSpec without having to subclass ASDisplayNode and
|
||||
* implement layoutSpecThatFits:
|
||||
*
|
||||
* @return The block used to provide a ASLayoutSpec
|
||||
*
|
||||
* @warning Overwriting layoutSpecThatFits: in a subclass and providing a layoutSpecBlock block is currently not supported
|
||||
*/
|
||||
@property (nonatomic, readwrite, copy, nullable) ASLayoutSpecBlock layoutSpecBlock;
|
||||
|
||||
/**
|
||||
* @abstract Return the calculated size.
|
||||
*
|
||||
|
||||
@@ -167,6 +167,14 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
return overrides;
|
||||
}
|
||||
|
||||
// At most a layoutSpecBlock or one of the three layout methods is overridden
|
||||
#define __ASDisplayNodeCheckForLayoutMethodOverrides \
|
||||
ASDisplayNodeAssert(_layoutSpecBlock != nil || \
|
||||
(ASDisplayNodeSubclassOverridesSelector(self.class, @selector(calculateSizeThatFits:)) ? 1 : 0) \
|
||||
+ (ASDisplayNodeSubclassOverridesSelector(self.class, @selector(layoutSpecThatFits:)) ? 1 : 0) \
|
||||
+ (ASDisplayNodeSubclassOverridesSelector(self.class, @selector(calculateLayoutThatFits:)) ? 1 : 0) <= 1, \
|
||||
@"Subclass %@ must at least provide a layoutSpecBlock or override at most one of the three layout methods: calculateLayoutThatFits, layoutSpecThatFits or calculateSizeThatFits", NSStringFromClass(self.class))
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self != [ASDisplayNode class]) {
|
||||
@@ -178,12 +186,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(measureWithSizeRange:)), @"Subclass %@ must not override measureWithSizeRange method", NSStringFromClass(self));
|
||||
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(recursivelyClearContents)), @"Subclass %@ must not override recursivelyClearContents method", NSStringFromClass(self));
|
||||
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(recursivelyClearFetchedData)), @"Subclass %@ must not override recursivelyClearFetchedData method", NSStringFromClass(self));
|
||||
|
||||
// At most one of the three layout methods is overridden
|
||||
ASDisplayNodeAssert((ASDisplayNodeSubclassOverridesSelector(self, @selector(calculateSizeThatFits:)) ? 1 : 0)
|
||||
+ (ASDisplayNodeSubclassOverridesSelector(self, @selector(layoutSpecThatFits:)) ? 1 : 0)
|
||||
+ (ASDisplayNodeSubclassOverridesSelector(self, @selector(calculateLayoutThatFits:)) ? 1 : 0) <= 1,
|
||||
@"Subclass %@ must override at most one of the three layout methods: calculateLayoutThatFits, layoutSpecThatFits or calculateSizeThatFits", NSStringFromClass(self));
|
||||
}
|
||||
|
||||
// Below we are pre-calculating values per-class and dynamically adding a method (_staticInitialize) to populate these values
|
||||
@@ -1848,8 +1850,10 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||
|
||||
- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize
|
||||
{
|
||||
__ASDisplayNodeCheckForLayoutMethodOverrides;
|
||||
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
if (_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits) {
|
||||
if ((_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits) || _layoutSpecBlock != nil) {
|
||||
ASLayoutSpec *layoutSpec = [self layoutSpecThatFits:constrainedSize];
|
||||
layoutSpec.parent = self; // This causes upward propogation of any non-default layoutable values.
|
||||
layoutSpec.isMutable = NO;
|
||||
@@ -1876,13 +1880,22 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||
|
||||
- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize
|
||||
{
|
||||
__ASDisplayNodeCheckForLayoutMethodOverrides;
|
||||
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
return _preferredFrameSize;
|
||||
}
|
||||
|
||||
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
|
||||
{
|
||||
__ASDisplayNodeCheckForLayoutMethodOverrides;
|
||||
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
|
||||
if (_layoutSpecBlock != nil) {
|
||||
return _layoutSpecBlock(constrainedSize);
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -1904,6 +1917,14 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||
return _constrainedSize;
|
||||
}
|
||||
|
||||
- (void)setLayoutSpecThatFitsBlock:(ASLayoutSpecBlock)layoutSpecBlock
|
||||
{
|
||||
// For now there should never be a overwrite of layoutSpecThatFits: and a layoutSpecThatFitsBlock: be provided
|
||||
ASDisplayNodeAssert(!(_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits), @"Overwriting layoutSpecThatFits: and providing a layoutSpecBlock block is currently not supported");
|
||||
|
||||
_layoutSpecBlock = layoutSpecBlock;
|
||||
}
|
||||
|
||||
- (void)setPendingTransitionID:(int32_t)pendingTransitionID
|
||||
{
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
|
||||
@interface ASSpecTestDisplayNode : ASDisplayNode
|
||||
|
||||
@property (copy, nonatomic) ASLayoutSpec * (^layoutSpecBlock)(ASSizeRange constrainedSize, NSNumber *layoutState);
|
||||
|
||||
/**
|
||||
Simple state identifier to allow control of current spec inside of the layoutSpecBlock
|
||||
*/
|
||||
@@ -37,11 +35,6 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
|
||||
{
|
||||
return self.layoutSpecBlock(constrainedSize, _layoutState);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface ASDisplayNodeImplicitHierarchyTests : XCTestCase
|
||||
@@ -83,7 +76,7 @@
|
||||
ASDisplayNode *node5 = [[ASDisplayNode alloc] init];
|
||||
|
||||
ASSpecTestDisplayNode *node = [[ASSpecTestDisplayNode alloc] init];
|
||||
node.layoutSpecBlock = ^(ASSizeRange constrainedSize, NSNumber *layoutState) {
|
||||
node.layoutSpecBlock = ^(ASSizeRange constrainedSize) {
|
||||
ASStaticLayoutSpec *staticLayout = [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[node4]];
|
||||
|
||||
ASStackLayoutSpec *stack1 = [[ASStackLayoutSpec alloc] init];
|
||||
@@ -109,8 +102,9 @@
|
||||
ASDisplayNode *node3 = [[ASDisplayNode alloc] init];
|
||||
|
||||
ASSpecTestDisplayNode *node = [[ASSpecTestDisplayNode alloc] init];
|
||||
node.layoutSpecBlock = ^(ASSizeRange constrainedSize, NSNumber *layoutState){
|
||||
if ([layoutState isEqualToNumber:@1]) {
|
||||
__weak ASSpecTestDisplayNode *weakNode = node;
|
||||
node.layoutSpecBlock = ^(ASSizeRange constrainedSize){
|
||||
if ([weakNode.layoutState isEqualToNumber:@1]) {
|
||||
return [ASStaticLayoutSpec staticLayoutSpecWithChildren:@[node1, node2]];
|
||||
} else {
|
||||
ASStackLayoutSpec *stackLayout = [[ASStackLayoutSpec alloc] init];
|
||||
|
||||
Reference in New Issue
Block a user