[ASDisplayNode] If We Skipped Rendering Due to Zero-Area, Re-Render When We Get a Real Area (#2149)

* Add failing test case

* [_ASDisplayLayer] If we skipped render due to being zero-size, enqueue a render when we get a real size

* Remove pointless import
This commit is contained in:
Adlai Holler
2016-08-26 15:51:49 -07:00
committed by GitHub
parent 8032758176
commit f542e8d458
3 changed files with 40 additions and 3 deletions

View File

@@ -301,7 +301,7 @@ struct ASImageNodeDrawParameters {
imageModificationBlock = drawParameter.imageModificationBlock;
}
BOOL hasValidCropBounds = cropEnabled && !CGRectIsNull(cropDisplayBounds) && !CGRectIsEmpty(cropDisplayBounds);
BOOL hasValidCropBounds = cropEnabled && !CGRectIsEmpty(cropDisplayBounds);
CGRect bounds = (hasValidCropBounds ? cropDisplayBounds : drawParameterBounds);
ASDisplayNodeContextModifier preContextBlock = self.willDisplayNodeContentWithRenderingContext;

View File

@@ -24,6 +24,7 @@
// We can take this lock when we're setting displaySuspended and in setNeedsDisplay, so to not deadlock, this is recursive
ASDN::RecursiveMutex _displaySuspendedLock;
BOOL _displaySuspended;
BOOL _attemptedDisplayWhileZeroSized;
struct {
BOOL delegateDidChangeBounds:1;
@@ -102,6 +103,11 @@
[super setBounds:bounds];
self.asyncdisplaykit_node.threadSafeBounds = bounds;
}
if (_attemptedDisplayWhileZeroSized && CGRectIsEmpty(bounds) == NO && self.needsDisplayOnBoundsChange == NO) {
_attemptedDisplayWhileZeroSized = NO;
[self setNeedsDisplay];
}
}
#if DEBUG // These override is strictly to help detect application-level threading errors. Avoid method overhead in release.
@@ -189,9 +195,9 @@
- (void)display
{
ASDisplayNodeAssertMainThread();
[self _hackResetNeedsDisplay];
ASDisplayNodeAssertMainThread();
if (self.isDisplaySuspended) {
return;
}
@@ -201,7 +207,11 @@
- (void)display:(BOOL)asynchronously
{
id<_ASDisplayLayerDelegate> __attribute__((objc_precise_lifetime)) strongAsyncDelegate;
if (CGRectIsEmpty(self.bounds)) {
_attemptedDisplayWhileZeroSized = YES;
}
id<_ASDisplayLayerDelegate> NS_VALID_UNTIL_END_OF_SCOPE strongAsyncDelegate;
{
_asyncDelegateLock.lock();
strongAsyncDelegate = _asyncDelegate;

View File

@@ -19,6 +19,7 @@
#import "ASDisplayNodeTestsHelper.h"
#import "UIView+ASConvenience.h"
#import "ASCellNode.h"
#import "ASImageNode.h"
// Conveniences for making nodes named a certain way
#define DeclareNodeNamed(n) ASDisplayNode *n = [[[ASDisplayNode alloc] init] autorelease]; n.name = @#n
@@ -1991,4 +1992,30 @@ static bool stringContainsPointer(NSString *description, const void *p) {
XCTAssert([node loadStateChangedToNO]);
}
- (void)testThatNodeGetsRenderedIfItGoesFromZeroSizeToRealSizeButOnlyOnce
{
NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"logo-square"
ofType:@"png" inDirectory:@"TestResources"];
UIImage *image = [UIImage imageWithContentsOfFile:path];
ASImageNode *node = [[[ASImageNode alloc] init] autorelease];
node.image = image;
// When rendered at zero-size, we get no contents
XCTAssert(CGSizeEqualToSize(node.bounds.size, CGSizeZero));
[node recursivelyEnsureDisplaySynchronously:YES];
XCTAssertNil(node.contents);
// When size becomes positive, we got some new contents
node.bounds = CGRectMake(0, 0, 100, 100);
[node recursivelyEnsureDisplaySynchronously:YES];
id contentsAfterRedisplay = node.contents;
XCTAssertNotNil(contentsAfterRedisplay);
// When size changes again, we do not get new contents
node.bounds = CGRectMake(0, 0, 1000, 1000);
[node recursivelyEnsureDisplaySynchronously:YES];
XCTAssertEqual(contentsAfterRedisplay, node.contents);
}
@end