Improve setting special properties for certain classes directly to the UIView

- Remove duplicated code in ASCollectionNode and ASTableNode
- Fix setting the pending state to the view if applying the pending state to the view
This commit is contained in:
Michael Schneider
2016-04-19 10:50:22 -07:00
parent 8d20321d67
commit 3793dc024e
7 changed files with 32 additions and 59 deletions

View File

@@ -16,11 +16,6 @@
@interface _ASCollectionPendingState : NSObject
@property (weak, nonatomic) id <ASCollectionDelegate> delegate;
@property (weak, nonatomic) id <ASCollectionDataSource> dataSource;
// If the background color is applied via the pending state it's applied to the layer of the UICollectionView.
// Unfortunately UICollectionView does not consider using the layer backgroundColor property as it's background color,
// so it needs to be applied to the view after the ASCollectionNode did load and the view is available
@property (strong, nonatomic) UIColor *backgroundColor;
@end
@implementation _ASCollectionPendingState
@@ -167,25 +162,6 @@
}
}
- (void)setBackgroundColor:(UIColor *)backgroundColor
{
if ([self pendingState]) {
_pendingState.backgroundColor = backgroundColor;
} else {
ASDisplayNodeAssert([self isNodeLoaded], @"ASTableNode should be loaded if pendingState doesn't exist");
self.view.backgroundColor = backgroundColor;
}
}
- (UIColor *)backgroundColor
{
if ([self pendingState]) {
return _pendingState.backgroundColor;
} else {
return self.view.backgroundColor;
}
}
- (ASCollectionView *)view
{
return (ASCollectionView *)[super view];

View File

@@ -83,6 +83,13 @@ BOOL ASDisplayNodeSubclassOverridesSelector(Class subclass, SEL selector)
return ASSubclassOverridesSelector([ASDisplayNode class], subclass, selector);
}
// For classes like ASTableNode, ASCollectionNode, ASScrollNode and similar - we have to be sure to set certain properties
// like setFrame: and setBackgroundColor: directly to the UIView and not apply it to the layer only.
BOOL ASDisplayNodeNeedsSpecialPropertiesSettingHandlingForFlags(ASDisplayNodeFlags flags)
{
return flags.synchronous && !flags.layerBacked;
}
_ASPendingState *ASDisplayNodeGetPendingState(ASDisplayNode *node)
{
ASDN::MutexLocker l(node->_propertyLock);
@@ -954,8 +961,8 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
if (self.layerBacked) {
[_pendingViewState applyToLayer:self.layer];
} else {
BOOL setFrameDirectly = (_flags.synchronous && !_flags.layerBacked);
[_pendingViewState applyToView:self.view setFrameDirectly:setFrameDirectly];
BOOL specialPropertiesHandling = ASDisplayNodeNeedsSpecialPropertiesSettingHandlingForFlags(_flags);
[_pendingViewState applyToView:self.view withSpecialPropertiesHandling:specialPropertiesHandling];
}
[_pendingViewState clearChanges];

View File

@@ -14,18 +14,13 @@
@interface _ASTablePendingState : NSObject
@property (weak, nonatomic) id <ASTableDelegate> delegate;
@property (weak, nonatomic) id <ASTableDataSource> dataSource;
// If the background color is applied via the pending state it's applied to the layer of the UITableView.
// Unfortunately UITableView does not consider using the layer backgroundColor property as it's background color,
// so it needs to be applied to the view after the ASTableNode did load and the view is available
@property (strong, nonatomic) UIColor *backgroundColor;
@end
@implementation _ASTablePendingState
@end
@interface ASTableNode ()
@property (nonatomic) _ASTablePendingState *pendingState;
@property (nonatomic, strong) _ASTablePendingState *pendingState;
@end
@interface ASTableView ()
@@ -79,7 +74,6 @@
self.pendingState = nil;
view.asyncDelegate = pendingState.delegate;
view.asyncDataSource = pendingState.dataSource;
view.backgroundColor = pendingState.backgroundColor;
}
}
@@ -139,25 +133,6 @@
}
}
- (void)setBackgroundColor:(UIColor *)backgroundColor
{
if ([self pendingState]) {
_pendingState.backgroundColor = backgroundColor;
} else {
ASDisplayNodeAssert([self isNodeLoaded], @"ASTableNode should be loaded if pendingState doesn't exist");
self.view.backgroundColor = backgroundColor;
}
}
- (UIColor *)backgroundColor
{
if ([self pendingState]) {
return _pendingState.backgroundColor;
} else {
return self.view.backgroundColor;
}
}
- (ASTableView *)view
{
return (ASTableView *)[super view];

View File

@@ -19,6 +19,7 @@
#import "ASPendingStateController.h"
#import "ASThread.h"
#import "ASTextNode.h"
#import "ASTableNode.h"
/**
* The following macros are conveniences to help in the common tasks related to the bridging that ASDisplayNode does to UIView and CALayer.
@@ -239,11 +240,11 @@ if (shouldApply) { _layer.layerProperty = (layerValueExpr); } else { ASDisplayNo
// For classes like ASTableNode, ASCollectionNode, ASScrollNode and similar - make sure UIView gets setFrame:
struct ASDisplayNodeFlags flags = _flags;
BOOL setFrameDirectly = flags.synchronous && !flags.layerBacked;
BOOL specialPropertiesHandling = ASDisplayNodeNeedsSpecialPropertiesSettingHandlingForFlags(flags);
BOOL nodeLoaded = __loaded(self);
BOOL isMainThread = ASDisplayNodeThreadIsMain();
if (!setFrameDirectly) {
if (!specialPropertiesHandling) {
BOOL canReadProperties = isMainThread || !nodeLoaded;
if (canReadProperties) {
// We don't have to set frame directly, and we can read current properties.
@@ -583,6 +584,12 @@ if (shouldApply) { _layer.layerProperty = (layerValueExpr); } else { ASDisplayNo
if (shouldApply) {
CGColorRef oldBackgroundCGColor = _layer.backgroundColor;
_layer.backgroundColor = newBackgroundCGColor;
BOOL specialPropertiesHandling = ASDisplayNodeNeedsSpecialPropertiesSettingHandlingForFlags(_flags);
if (specialPropertiesHandling) {
_view.backgroundColor = newBackgroundColor;
}
if (!CGColorEqualToColor(oldBackgroundCGColor, newBackgroundCGColor)) {
[self setNeedsDisplay];
}

View File

@@ -25,8 +25,10 @@
@class _ASDisplayLayer;
@class _ASPendingState;
@class ASSentinel;
struct ASDisplayNodeFlags;
BOOL ASDisplayNodeSubclassOverridesSelector(Class subclass, SEL selector);
BOOL ASDisplayNodeNeedsSpecialPropertiesSettingHandlingForFlags(ASDisplayNodeFlags flags);
/// Get the pending view state for the node, creating one if needed.
_ASPendingState *ASDisplayNodeGetPendingState(ASDisplayNode *node);

View File

@@ -24,7 +24,7 @@
// Supports all of the properties included in the ASDisplayNodeViewProperties protocol
- (void)applyToView:(UIView *)view setFrameDirectly:(BOOL)setFrameDirectly;
- (void)applyToView:(UIView *)view withSpecialPropertiesHandling:(BOOL)setFrameDirectly;
- (void)applyToLayer:(CALayer *)layer;
+ (_ASPendingState *)pendingViewStateFromLayer:(CALayer *)layer;

View File

@@ -745,7 +745,7 @@ static UIColor *defaultTintColor = nil;
ASPendingStateApplyMetricsToLayer(self, layer);
}
- (void)applyToView:(UIView *)view setFrameDirectly:(BOOL)setFrameDirectly
- (void)applyToView:(UIView *)view withSpecialPropertiesHandling:(BOOL)specialPropertiesHandling
{
/*
Use our convenience setters blah here instead of layer.blah
@@ -789,9 +789,16 @@ static UIColor *defaultTintColor = nil;
if (flags.setClipsToBounds)
view.clipsToBounds = clipsToBounds;
if (flags.setBackgroundColor)
if (flags.setBackgroundColor) {
// Set the background color to the layer as in the UIView bridge we use this value as background color
layer.backgroundColor = backgroundColor;
// We have to make sure certain nodes get the background color call directly
if (specialPropertiesHandling) {
view.backgroundColor = [UIColor colorWithCGColor:backgroundColor];
}
}
if (flags.setTintColor)
view.tintColor = self.tintColor;
@@ -907,8 +914,7 @@ static UIColor *defaultTintColor = nil;
if (flags.setAccessibilityPath)
view.accessibilityPath = accessibilityPath;
// For classes like ASTableNode, ASCollectionNode, ASScrollNode and similar - make sure UIView gets setFrame:
if (flags.setFrame && setFrameDirectly) {
if (flags.setFrame && specialPropertiesHandling) {
// Frame is only defined when transform is identity because we explicitly diverge from CALayer behavior and define frame without transform
#if DEBUG
// Checking if the transform is identity is expensive, so disable when unnecessary. We have assertions on in Release, so DEBUG is the only way I know of.