mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-24 07:05:35 +00:00
Cleanup calculateLayoutThatFits: (#2480)
This commit is contained in:
committed by
Adlai Holler
parent
12534ee6fb
commit
6d5bd6e969
@@ -63,9 +63,6 @@ typedef struct {
|
||||
+ (BOOL)suppressesInvalidCollectionUpdateExceptions AS_WARN_UNUSED_RESULT;
|
||||
+ (void)setSuppressesInvalidCollectionUpdateExceptions:(BOOL)suppresses;
|
||||
|
||||
/** @name Layout */
|
||||
|
||||
|
||||
/**
|
||||
* @abstract Recursively ensures node and all subnodes are displayed.
|
||||
* @see Full documentation in ASDisplayNode+FrameworkPrivate.h
|
||||
@@ -97,8 +94,6 @@ typedef struct {
|
||||
*/
|
||||
@property (nonatomic, assign, readonly) ASDisplayNodePerformanceMeasurements performanceMeasurements;
|
||||
|
||||
/** @name Layout Transitioning */
|
||||
|
||||
/**
|
||||
* @abstract Currently used by ASNetworkImageNode and ASMultiplexImageNode to allow their placeholders to stay if they are loading an image from the network.
|
||||
* Otherwise, a display pass is scheduled and completes, but does not actually draw anything - and ASDisplayNode considers the element finished.
|
||||
|
||||
@@ -41,6 +41,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ASDisplayNode (Subclassing)
|
||||
|
||||
#pragma mark - Properties
|
||||
/** @name Properties */
|
||||
|
||||
/**
|
||||
@@ -64,9 +65,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
@property (nullable, nonatomic, readonly, assign) ASLayout *calculatedLayout;
|
||||
|
||||
#pragma mark - View Lifecycle
|
||||
/** @name View Lifecycle */
|
||||
|
||||
|
||||
/**
|
||||
* @abstract Called on the main thread immediately after self.view is created.
|
||||
*
|
||||
@@ -75,9 +76,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (void)didLoad ASDISPLAYNODE_REQUIRES_SUPER;
|
||||
|
||||
|
||||
#pragma mark - Layout
|
||||
/** @name Layout */
|
||||
|
||||
|
||||
/**
|
||||
* @abstract Called on the main thread by the view's -layoutSubviews.
|
||||
*
|
||||
@@ -101,6 +102,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
- (void)calculatedLayoutDidChange ASDISPLAYNODE_REQUIRES_SUPER;
|
||||
|
||||
|
||||
#pragma mark - Layout calculation
|
||||
/** @name Layout calculation */
|
||||
|
||||
/**
|
||||
@@ -159,9 +162,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*
|
||||
* @note This method should not be called directly outside of ASDisplayNode; use -measure: or -calculatedLayout instead.
|
||||
*
|
||||
* @warning Subclasses that implement -layoutSpecThatFits: must not also use .layoutSpecBlock. Doing so will trigger
|
||||
* an exception. A future version of the framework may support using both, calling them serially, with the
|
||||
* .layoutSpecBlock superseding any values set by the method override.
|
||||
* @warning Subclasses that implement -layoutSpecThatFits: must not use .layoutSpecBlock. Doing so will trigger an
|
||||
* exception. A future version of the framework may support using both, calling them serially, with the .layoutSpecBlock
|
||||
* superseding any values set by the method override.
|
||||
*/
|
||||
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize;
|
||||
|
||||
@@ -174,9 +177,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (void)invalidateCalculatedLayout;
|
||||
|
||||
|
||||
#pragma mark - Drawing
|
||||
/** @name Drawing */
|
||||
|
||||
|
||||
/**
|
||||
* @summary Delegate method to draw layer contents into a CGBitmapContext. The current UIGraphics context will be set
|
||||
* to an appropriate context.
|
||||
@@ -407,9 +410,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic, assign, readonly) CGFloat contentsScaleForDisplay;
|
||||
|
||||
|
||||
#pragma mark - Touch handling
|
||||
/** @name Touch handling */
|
||||
|
||||
|
||||
/**
|
||||
* @abstract Tells the node when touches began in its view.
|
||||
*
|
||||
@@ -443,9 +446,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (void)touchesCancelled:(nullable NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event ASDISPLAYNODE_REQUIRES_SUPER;
|
||||
|
||||
|
||||
#pragma mark - Managing Gesture Recognizers
|
||||
/** @name Managing Gesture Recognizers */
|
||||
|
||||
|
||||
/**
|
||||
* @abstract Asks the node if a gesture recognizer should continue tracking touches.
|
||||
*
|
||||
@@ -454,8 +457,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;
|
||||
|
||||
|
||||
/** @name Hit Testing */
|
||||
#pragma mark - Hit Testing
|
||||
|
||||
/** @name Hit Testing */
|
||||
|
||||
/**
|
||||
* @abstract Returns the view that contains the point.
|
||||
@@ -472,6 +476,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
|
||||
|
||||
|
||||
#pragma mark - Placeholders
|
||||
/** @name Placeholders */
|
||||
|
||||
/**
|
||||
@@ -492,6 +498,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (nullable UIImage *)placeholderImage;
|
||||
|
||||
|
||||
#pragma mark - Description
|
||||
/** @name Description */
|
||||
|
||||
/**
|
||||
|
||||
@@ -186,10 +186,10 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
// At most a layoutSpecBlock or one of the three layout methods is overridden
|
||||
#define __ASDisplayNodeCheckForLayoutMethodOverrides \
|
||||
ASDisplayNodeAssert(_layoutSpecBlock != NULL || \
|
||||
(ASDisplayNodeSubclassOverridesSelector(self.class, @selector(calculateSizeThatFits:)) ? 1 : 0) \
|
||||
((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))
|
||||
+ (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
|
||||
{
|
||||
@@ -199,14 +199,14 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
// Subclasses should never override these. Use unused to prevent warnings
|
||||
__unused NSString *classString = NSStringFromClass(self);
|
||||
|
||||
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(calculatedSize)), @"Subclass %@ must not override calculatedSize method", classString);
|
||||
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(calculatedLayout)), @"Subclass %@ must not override calculatedLayout method", classString);
|
||||
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(calculatedSize)), @"Subclass %@ must not override calculatedSize method.", classString);
|
||||
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(calculatedLayout)), @"Subclass %@ must not override calculatedLayout method.", classString);
|
||||
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(measure:)), @"Subclass %@ must not override measure: method", classString);
|
||||
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(measureWithSizeRange:)), @"Subclass %@ must not override measureWithSizeRange: method. Instead overwrite calculateLayoutThatFits:", classString);
|
||||
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(layoutThatFits:)), @"Subclass %@ must not override layoutThatFits: method", classString);
|
||||
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(layoutThatFits:parentSize:)), @"Subclass %@ must not override layoutThatFits:parentSize method", classString);
|
||||
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(recursivelyClearContents)), @"Subclass %@ must not override recursivelyClearContents method", classString);
|
||||
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(recursivelyClearFetchedData)), @"Subclass %@ must not override recursivelyClearFetchedData method", classString);
|
||||
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(layoutThatFits:)), @"Subclass %@ must not override layoutThatFits: method. Instead overwrite calculateLayoutThatFits:.", classString);
|
||||
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(layoutThatFits:parentSize:)), @"Subclass %@ must not override layoutThatFits:parentSize method. Instead overwrite calculateLayoutThatFits:.", classString);
|
||||
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(recursivelyClearContents)), @"Subclass %@ must not override recursivelyClearContents method.", classString);
|
||||
ASDisplayNodeAssert(!ASDisplayNodeSubclassOverridesSelector(self, @selector(recursivelyClearFetchedData)), @"Subclass %@ must not override recursivelyClearFetchedData method.", classString);
|
||||
}
|
||||
|
||||
// Below we are pre-calculating values per-class and dynamically adding a method (_staticInitialize) to populate these values
|
||||
@@ -232,18 +232,17 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
|
||||
|
||||
#if DEBUG
|
||||
// Check if subnodes where modified during layoutSpecThatFits:
|
||||
if (self == [ASDisplayNode class] || ASSubclassOverridesSelector([ASDisplayNode class], self, @selector(layoutSpecThatFits:)))
|
||||
{
|
||||
__block IMP originalLayoutSpecThatFitsIMP = ASReplaceMethodWithBlock(self, @selector(layoutSpecThatFits:), ^(ASDisplayNode *_self, ASSizeRange sizeRange) {
|
||||
// Check if subnodes where modified during the creation of the layout
|
||||
if (self == [ASDisplayNode class]) {
|
||||
__block IMP originalLayoutSpecThatFitsIMP = ASReplaceMethodWithBlock(self, @selector(_layoutElementThatFits:), ^(ASDisplayNode *_self, ASSizeRange sizeRange) {
|
||||
NSArray *oldSubnodes = _self.subnodes;
|
||||
ASLayoutSpec *layoutSpec = ((ASLayoutSpec *( *)(id, SEL, ASSizeRange))originalLayoutSpecThatFitsIMP)(_self, @selector(layoutSpecThatFits:), sizeRange);
|
||||
ASLayoutSpec *layoutElement = ((ASLayoutSpec *( *)(id, SEL, ASSizeRange))originalLayoutSpecThatFitsIMP)(_self, @selector(_layoutElementThatFits:), sizeRange);
|
||||
NSArray *subnodes = _self.subnodes;
|
||||
ASDisplayNodeAssert(oldSubnodes.count == subnodes.count, @"Adding or removing nodes in layoutSpecThatFits: is verboten.");
|
||||
ASDisplayNodeAssert(oldSubnodes.count == subnodes.count, @"Adding or removing nodes in layoutSpecBlock or layoutSpecThatFits: is not allowed and can cause unexpected behavior.");
|
||||
for (NSInteger i = 0; i < oldSubnodes.count; i++) {
|
||||
ASDisplayNodeAssert(oldSubnodes[i] == subnodes[i], @"Adding and removing nodes in layoutSpecThatFits: is verboten.");
|
||||
ASDisplayNodeAssert(oldSubnodes[i] == subnodes[i], @"Adding or removing nodes in layoutSpecBlock or layoutSpecThatFits: is not allowed and can cause unexpected behavior.");
|
||||
}
|
||||
return layoutSpec;
|
||||
return layoutElement;
|
||||
});
|
||||
}
|
||||
#endif
|
||||
@@ -2425,62 +2424,67 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||
__ASDisplayNodeCheckForLayoutMethodOverrides;
|
||||
|
||||
ASDN::MutexLocker l(__instanceLock__);
|
||||
if ((_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits) || _layoutSpecBlock != NULL) {
|
||||
BOOL measureLayoutSpec = _measurementOptions & ASDisplayNodePerformanceMeasurementOptionLayoutSpec;
|
||||
if (measureLayoutSpec) {
|
||||
_layoutSpecNumberOfPasses++;
|
||||
}
|
||||
|
||||
ASLayoutSpec *layoutSpec = ({
|
||||
ASDN::SumScopeTimer t(_layoutSpecTotalTime, measureLayoutSpec);
|
||||
[self layoutSpecThatFits:constrainedSize];
|
||||
});
|
||||
|
||||
#if AS_DEDUPE_LAYOUT_SPEC_TREE
|
||||
NSSet *duplicateElements = [layoutSpec findDuplicatedElementsInSubtree];
|
||||
if (duplicateElements.count > 0) {
|
||||
ASDisplayNodeFailAssert(@"Node %@ returned a layout spec that contains the same elements in multiple positions. Elements: %@", self, duplicateElements);
|
||||
// Use an empty layout spec to avoid crash.
|
||||
layoutSpec = [[ASLayoutSpec alloc] init];
|
||||
}
|
||||
#endif
|
||||
|
||||
ASDisplayNodeAssert(layoutSpec.isMutable, @"Node %@ returned layout spec %@ that has already been used. Layout specs should always be regenerated.", self, layoutSpec);
|
||||
|
||||
layoutSpec.parent = self; // This causes upward propogation of any non-default layoutElement values.
|
||||
|
||||
// manually propagate the trait collection here so that any layoutSpec children of layoutSpec will get a traitCollection
|
||||
{
|
||||
ASDN::SumScopeTimer t(_layoutSpecTotalTime, measureLayoutSpec);
|
||||
ASEnvironmentStatePropagateDown(layoutSpec, self.environmentTraitCollection);
|
||||
}
|
||||
|
||||
layoutSpec.isMutable = NO;
|
||||
BOOL measureLayoutComputation = _measurementOptions & ASDisplayNodePerformanceMeasurementOptionLayoutComputation;
|
||||
if (measureLayoutComputation) {
|
||||
_layoutComputationNumberOfPasses++;
|
||||
}
|
||||
|
||||
ASLayout *layout = ({
|
||||
ASDN::SumScopeTimer t(_layoutComputationTotalTime, measureLayoutComputation);
|
||||
[layoutSpec layoutThatFits:constrainedSize];
|
||||
});
|
||||
|
||||
ASDisplayNodeAssertNotNil(layout, @"[ASLayoutSpec measureWithSizeRange:] should never return nil! %@, %@", self, layoutSpec);
|
||||
|
||||
// Make sure layoutElementObject of the root layout is `self`, so that the flattened layout will be structurally correct.
|
||||
BOOL isFinalLayoutElement = (layout.layoutElement != self);
|
||||
if (isFinalLayoutElement) {
|
||||
layout.position = CGPointZero;
|
||||
layout = [ASLayout layoutWithLayoutElement:self size:layout.size sublayouts:@[layout]];
|
||||
}
|
||||
ASDisplayNodeLogEvent(self, @"computedLayout: %@", layout);
|
||||
return [layout filteredNodeLayoutTree];
|
||||
} else {
|
||||
// Manual size calculation via calculateSizeThatFits:
|
||||
if (((_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits) ||
|
||||
(_layoutSpecBlock != NULL)) == NO) {
|
||||
CGSize size = [self calculateSizeThatFits:constrainedSize.max];
|
||||
ASDisplayNodeLogEvent(self, @"calculatedSize: %@", NSStringFromCGSize(size));
|
||||
return [ASLayout layoutWithLayoutElement:self size:ASSizeRangeClamp(constrainedSize, size) sublayouts:nil];
|
||||
}
|
||||
|
||||
// Size calcualtion with layout elements
|
||||
BOOL measureLayoutSpec = _measurementOptions & ASDisplayNodePerformanceMeasurementOptionLayoutSpec;
|
||||
if (measureLayoutSpec) {
|
||||
_layoutSpecNumberOfPasses++;
|
||||
}
|
||||
|
||||
// Get layout element from the node
|
||||
id<ASLayoutElement> layoutElement = [self _layoutElementThatFits:constrainedSize];
|
||||
|
||||
// Certain properties are necessary to set on an element of type ASLayoutSpec
|
||||
if (layoutElement.layoutElementType == ASLayoutElementTypeLayoutSpec) {
|
||||
ASLayoutSpec *layoutSpec = (ASLayoutSpec *)layoutElement;
|
||||
|
||||
NSSet *duplicateElements = [layoutSpec findDuplicatedElementsInSubtree];
|
||||
if (duplicateElements.count > 0) {
|
||||
ASDisplayNodeFailAssert(@"Node %@ returned a layout spec that contains the same elements in multiple positions. Elements: %@", self, duplicateElements);
|
||||
// Use an empty layout spec to avoid crashes
|
||||
layoutSpec = [[ASLayoutSpec alloc] init];
|
||||
}
|
||||
|
||||
ASDisplayNodeAssert(layoutSpec.isMutable, @"Node %@ returned layout spec %@ that has already been used. Layout specs should always be regenerated.", self, layoutSpec);
|
||||
layoutSpec.parent = self;
|
||||
layoutSpec.isMutable = NO;
|
||||
}
|
||||
|
||||
// Manually propagate the trait collection here so that any layoutSpec children of layoutSpec will get a traitCollection
|
||||
{
|
||||
ASDN::SumScopeTimer t(_layoutSpecTotalTime, measureLayoutSpec);
|
||||
ASEnvironmentStatePropagateDown(layoutElement, [self environmentTraitCollection]);
|
||||
}
|
||||
|
||||
BOOL measureLayoutComputation = _measurementOptions & ASDisplayNodePerformanceMeasurementOptionLayoutComputation;
|
||||
if (measureLayoutComputation) {
|
||||
_layoutComputationNumberOfPasses++;
|
||||
}
|
||||
|
||||
// Layout element layout creation
|
||||
ASLayout *layout = ({
|
||||
ASDN::SumScopeTimer t(_layoutComputationTotalTime, measureLayoutComputation);
|
||||
[layoutElement layoutThatFits:constrainedSize];
|
||||
});
|
||||
ASDisplayNodeAssertNotNil(layout, @"[ASLayoutElement layoutThatFits:] should never return nil! %@, %@", self, layout);
|
||||
|
||||
// Make sure layoutElementObject of the root layout is `self`, so that the flattened layout will be structurally correct.
|
||||
BOOL isFinalLayoutElement = (layout.layoutElement != self);
|
||||
if (isFinalLayoutElement) {
|
||||
layout.position = CGPointZero;
|
||||
layout = [ASLayout layoutWithLayoutElement:self size:layout.size sublayouts:@[layout]];
|
||||
}
|
||||
ASDisplayNodeLogEvent(self, @"computedLayout: %@", layout);
|
||||
|
||||
return [layout filteredNodeLayoutTree];
|
||||
}
|
||||
|
||||
- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize
|
||||
@@ -2490,15 +2494,28 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||
return CGSizeZero;
|
||||
}
|
||||
|
||||
- (id<ASLayoutElement>)_layoutElementThatFits:(ASSizeRange)constrainedSize
|
||||
{
|
||||
__ASDisplayNodeCheckForLayoutMethodOverrides;
|
||||
|
||||
BOOL measureLayoutSpec = _measurementOptions & ASDisplayNodePerformanceMeasurementOptionLayoutSpec;
|
||||
if (_layoutSpecBlock != NULL) {
|
||||
return ({
|
||||
ASDN::MutexLocker l(__instanceLock__);
|
||||
ASDN::SumScopeTimer t(_layoutSpecTotalTime, measureLayoutSpec);
|
||||
_layoutSpecBlock(self, constrainedSize);
|
||||
});
|
||||
} else {
|
||||
return ({
|
||||
ASDN::SumScopeTimer t(_layoutSpecTotalTime, measureLayoutSpec);
|
||||
[self layoutSpecThatFits:constrainedSize];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
|
||||
{
|
||||
__ASDisplayNodeCheckForLayoutMethodOverrides;
|
||||
|
||||
ASDN::MutexLocker l(__instanceLock__);
|
||||
|
||||
if (_layoutSpecBlock != NULL) {
|
||||
return _layoutSpecBlock(self, constrainedSize);
|
||||
}
|
||||
|
||||
ASDisplayNodeAssert(NO, @"-[ASDisplayNode layoutSpecThatFits:] should never return an empty value. One way this is caused is by calling -[super layoutSpecThatFits:] which is not currently supported.");
|
||||
return [[ASLayoutSpec alloc] init];
|
||||
@@ -2506,7 +2523,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||
|
||||
- (void)setLayoutSpecBlock:(ASLayoutSpecBlock)layoutSpecBlock
|
||||
{
|
||||
// For now there should never be a overwrite of layoutSpecThatFits: and a layoutSpecThatFitsBlock: be provided
|
||||
// For now there should never be an overwrite of layoutSpecThatFits: / layoutElementThatFits: and a layoutSpecBlock
|
||||
ASDisplayNodeAssert(!(_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits), @"Overwriting layoutSpecThatFits: and providing a layoutSpecBlock block is currently not supported");
|
||||
|
||||
ASDN::MutexLocker l(__instanceLock__);
|
||||
@@ -3421,11 +3438,6 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority";
|
||||
return self.subnodes;
|
||||
}
|
||||
|
||||
- (BOOL)supportsUpwardPropagation
|
||||
{
|
||||
return ASEnvironmentStatePropagationEnabled();
|
||||
}
|
||||
|
||||
- (BOOL)supportsTraitsCollectionPropagation
|
||||
{
|
||||
return ASEnvironmentStateTraitCollectionPropagationEnabled();
|
||||
|
||||
@@ -110,8 +110,9 @@ ASDISPLAYNODE_EXTERN_C_END
|
||||
/// Returns all children of an object which class conforms to the ASEnvironment protocol
|
||||
- (nullable NSArray<id<ASEnvironment>> *)children;
|
||||
|
||||
/// Classes should implement this method and return YES / NO dependent if upward propagation is enabled or not
|
||||
- (BOOL)supportsUpwardPropagation;
|
||||
/// Classes should implement this method and return YES / NO dependent if upward propagation is enabled or not
|
||||
// Currently this is disabled as propagation of any attributions besides trait collections is not supported at the moment
|
||||
// - (BOOL)supportsUpwardPropagation;
|
||||
|
||||
/// Classes should implement this method and return YES / NO dependent if downware propagation is enabled or not
|
||||
- (BOOL)supportsTraitsCollectionPropagation;
|
||||
|
||||
@@ -100,16 +100,6 @@
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - ASEnvironment
|
||||
|
||||
@implementation ASAbsoluteLayoutSpec (ASEnvironment)
|
||||
|
||||
- (BOOL)supportsUpwardPropagation
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Debugging
|
||||
|
||||
|
||||
@@ -88,10 +88,6 @@
|
||||
|
||||
// Replace object at the given index with the layoutElement
|
||||
_childrenArray[index] = layoutElement;
|
||||
|
||||
// TODO: Should we propagate up the layoutElement at it could happen that multiple children will propagated up their
|
||||
// layout options and one child will overwrite values from another child
|
||||
// [self propagateUpLayoutElement:finalLayoutElement];
|
||||
}
|
||||
|
||||
- (id<ASLayoutElement>)childAtIndex:(NSUInteger)index
|
||||
|
||||
@@ -105,19 +105,6 @@
|
||||
return [ASLayout layoutWithLayoutElement:self size:constrainedSize.min];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Parent
|
||||
|
||||
- (void)setParent:(id<ASLayoutElement>)parent
|
||||
{
|
||||
// FIXME: Locking should be evaluated here. _parent is not widely used yet, though.
|
||||
_parent = parent;
|
||||
|
||||
if ([parent supportsUpwardPropagation]) {
|
||||
ASEnvironmentStatePropagateUp(parent, self.environmentState.layoutOptionsState);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Child
|
||||
|
||||
- (void)setChild:(id<ASLayoutElement>)child
|
||||
@@ -129,7 +116,6 @@
|
||||
id<ASLayoutElement> finalLayoutElement = [self layoutElementToAddFromLayoutElement:child];
|
||||
if (finalLayoutElement) {
|
||||
_childrenArray[0] = finalLayoutElement;
|
||||
[self propagateUpLayoutElement:finalLayoutElement];
|
||||
}
|
||||
} else {
|
||||
if (_childrenArray.count) {
|
||||
@@ -185,28 +171,11 @@
|
||||
_environmentState = environmentState;
|
||||
}
|
||||
|
||||
// Subclasses can override this method to return NO, because upward propagation is not enabled if a layout
|
||||
// specification has more than one child. Currently ASStackLayoutSpec and ASAbsoluteLayoutSpec are currently
|
||||
// the specifications that are known to have more than one.
|
||||
- (BOOL)supportsUpwardPropagation
|
||||
{
|
||||
return ASEnvironmentStatePropagationEnabled();
|
||||
}
|
||||
|
||||
- (BOOL)supportsTraitsCollectionPropagation
|
||||
{
|
||||
return ASEnvironmentStateTraitCollectionPropagationEnabled();
|
||||
}
|
||||
|
||||
- (void)propagateUpLayoutElement:(id<ASLayoutElement>)layoutElement
|
||||
{
|
||||
if ([layoutElement isKindOfClass:[ASLayoutSpec class]]) {
|
||||
[(ASLayoutSpec *)layoutElement setParent:self]; // This will trigger upward propogation if needed.
|
||||
} else if ([self supportsUpwardPropagation]) {
|
||||
ASEnvironmentStatePropagateUp(self, layoutElement.environmentState.layoutOptionsState); // Probably an ASDisplayNode
|
||||
}
|
||||
}
|
||||
|
||||
- (ASEnvironmentTraitCollection)environmentTraitCollection
|
||||
{
|
||||
return _environmentState.environmentTraitCollection;
|
||||
|
||||
@@ -182,15 +182,6 @@
|
||||
|
||||
@end
|
||||
|
||||
@implementation ASStackLayoutSpec (ASEnvironment)
|
||||
|
||||
- (BOOL)supportsUpwardPropagation
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation ASStackLayoutSpec (Debugging)
|
||||
|
||||
#pragma mark - ASLayoutElementAsciiArtProtocol
|
||||
|
||||
@@ -45,8 +45,7 @@
|
||||
{
|
||||
ASStackLayoutSpec *verticalStack = [ASStackLayoutSpec verticalStackLayoutSpec];
|
||||
verticalStack.spacing = INTER_COMMENT_SPACING;
|
||||
[verticalStack setChildren:_commentNodes];
|
||||
|
||||
verticalStack.children = [_commentNodes copy];
|
||||
return verticalStack;
|
||||
}
|
||||
|
||||
|
||||
@@ -116,30 +116,26 @@
|
||||
_photoLocationLabel.style.flexShrink = 1.0;
|
||||
_userNameLabel.style.flexShrink = 1.0;
|
||||
|
||||
ASStackLayoutSpec *headerSubStack = [ASStackLayoutSpec verticalStackLayoutSpec];
|
||||
ASStackLayoutSpec *headerSubStack = [ASStackLayoutSpec verticalStackLayoutSpec];
|
||||
headerSubStack.style.flexShrink = 1.0;
|
||||
if (_photoLocationLabel.attributedText) {
|
||||
[headerSubStack setChildren:@[_userNameLabel, _photoLocationLabel]];
|
||||
} else {
|
||||
[headerSubStack setChildren:@[_userNameLabel]];
|
||||
}
|
||||
|
||||
headerSubStack.children = _photoLocationLabel.attributedText ? @[_userNameLabel, _photoLocationLabel]
|
||||
: @[_userNameLabel];
|
||||
// header stack
|
||||
|
||||
// constrain avatar image frame size
|
||||
_userAvatarImageView.style.preferredSize = CGSizeMake(USER_IMAGE_HEIGHT, USER_IMAGE_HEIGHT);
|
||||
_photoTimeIntervalSincePostLabel.style.spacingBefore = HORIZONTAL_BUFFER; // to remove double spaces around spacer
|
||||
_photoTimeIntervalSincePostLabel.style.spacingBefore = HORIZONTAL_BUFFER; // to remove double spaces around spacer
|
||||
|
||||
ASLayoutSpec *spacer = [[ASLayoutSpec alloc] init]; // FIXME: long locations overflow post time - set max size?
|
||||
ASLayoutSpec *spacer = [[ASLayoutSpec alloc] init]; // FIXME: long locations overflow post time - set max size?
|
||||
spacer.style.flexGrow = 1.0;
|
||||
|
||||
UIEdgeInsets avatarInsets = UIEdgeInsetsMake(HORIZONTAL_BUFFER, 0, HORIZONTAL_BUFFER, HORIZONTAL_BUFFER);
|
||||
ASInsetLayoutSpec *avatarInset = [ASInsetLayoutSpec insetLayoutSpecWithInsets:avatarInsets child:_userAvatarImageView];
|
||||
|
||||
ASStackLayoutSpec *headerStack = [ASStackLayoutSpec horizontalStackLayoutSpec];
|
||||
headerStack.alignItems = ASStackLayoutAlignItemsCenter; // center items vertically in horizontal stack
|
||||
headerStack.justifyContent = ASStackLayoutJustifyContentStart; // justify content to the left side of the header stack
|
||||
[headerStack setChildren:@[avatarInset, headerSubStack, spacer, _photoTimeIntervalSincePostLabel]];
|
||||
headerStack.alignItems = ASStackLayoutAlignItemsCenter; // center items vertically in horizontal stack
|
||||
headerStack.justifyContent = ASStackLayoutJustifyContentStart; // justify content to the left side of the header stack
|
||||
headerStack.children = @[avatarInset, headerSubStack, spacer, _photoTimeIntervalSincePostLabel];
|
||||
|
||||
// header inset stack
|
||||
UIEdgeInsets insets = UIEdgeInsetsMake(0, HORIZONTAL_BUFFER, 0, HORIZONTAL_BUFFER);
|
||||
@@ -148,7 +144,7 @@
|
||||
// footer stack
|
||||
ASStackLayoutSpec *footerStack = [ASStackLayoutSpec verticalStackLayoutSpec];
|
||||
footerStack.spacing = VERTICAL_BUFFER;
|
||||
[footerStack setChildren:@[_photoLikesLabel, _photoDescriptionLabel, _photoCommentsView]];
|
||||
footerStack.children = @[_photoLikesLabel, _photoDescriptionLabel, _photoCommentsView];
|
||||
|
||||
// footer inset stack
|
||||
UIEdgeInsets footerInsets = UIEdgeInsetsMake(VERTICAL_BUFFER, HORIZONTAL_BUFFER, VERTICAL_BUFFER, HORIZONTAL_BUFFER);
|
||||
@@ -161,8 +157,8 @@
|
||||
_photoImageView.style.preferredSize = CGSizeMake(cellWidth, cellWidth);
|
||||
|
||||
ASStackLayoutSpec *verticalStack = [ASStackLayoutSpec verticalStackLayoutSpec];
|
||||
verticalStack.alignItems = ASStackLayoutAlignItemsStretch; // stretch headerStack to fill horizontal space
|
||||
[verticalStack setChildren:@[headerWithInset, _photoImageView, footerWithInset]];
|
||||
verticalStack.alignItems = ASStackLayoutAlignItemsStretch; // stretch headerStack to fill horizontal space
|
||||
verticalStack.children = @[headerWithInset, _photoImageView, footerWithInset];
|
||||
|
||||
return verticalStack;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user