mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 14:20:20 +00:00
[ASDisplayNode] Placeholders should always be recreated if returning to past nodes.
If previously-displayed contents is gone (e.g. clearContents), and is not finished displaying by the time the node is onscreen, recreate the placeholder immediately.
This commit is contained in:
@@ -420,6 +420,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
{
|
||||
CALayer *layer;
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
ASDisplayNodeAssert(_flags.layerBacked, @"_layerToLoad is only for layer-backed nodes");
|
||||
|
||||
if (_layerBlock) {
|
||||
layer = _layerBlock();
|
||||
@@ -475,10 +476,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
TIME_SCOPED(_debugTimeForDidLoad);
|
||||
[self __didLoad];
|
||||
}
|
||||
|
||||
if (self.placeholderEnabled) {
|
||||
[self _setupPlaceholderLayer];
|
||||
}
|
||||
}
|
||||
|
||||
- (UIView *)view
|
||||
@@ -743,17 +740,20 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
[self calculatedLayoutDidChange];
|
||||
|
||||
// we generate placeholders at measureWithSizeRange: time so that a node is guaranteed
|
||||
// to have a placeholder ready to go. Also, if a node has no size it should not have a placeholder
|
||||
if (self.placeholderEnabled && [self _displaysAsynchronously] &&
|
||||
_layout.size.width > 0.0 && _layout.size.height > 0.0) {
|
||||
// We generate placeholders at measureWithSizeRange: time so that a node is guaranteed to have a placeholder ready to go.
|
||||
// This is also because measurement is usually asynchronous, but placeholders need to be set up synchronously.
|
||||
// First measurement is guaranteed to be before the node is onscreen, so we can create the image async. but still have it appear sync.
|
||||
if (_placeholderEnabled && [self _displaysAsynchronously] && self.contents == nil) {
|
||||
|
||||
// Zero-sized nodes do not require a placeholder.
|
||||
CGSize layoutSize = (_layout ? _layout.size : CGSizeZero);
|
||||
if (CGSizeEqualToSize(layoutSize, CGSizeZero)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_placeholderImage) {
|
||||
_placeholderImage = [self placeholderImage];
|
||||
}
|
||||
|
||||
if (_placeholderLayer) {
|
||||
[self _setupPlaceholderLayerContents];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1004,13 +1004,14 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
ASDN::MutexLocker l(_propertyLock);
|
||||
if (CGRectEqualToRect(self.bounds, CGRectZero)) {
|
||||
CGRect bounds = self.bounds;
|
||||
if (CGRectEqualToRect(bounds, CGRectZero)) {
|
||||
// Performing layout on a zero-bounds view often results in frame calculations
|
||||
// with negative sizes after applying margins, which will cause
|
||||
// measureWithSizeRange: on subnodes to assert.
|
||||
return;
|
||||
}
|
||||
_placeholderLayer.frame = self.bounds;
|
||||
_placeholderLayer.frame = bounds;
|
||||
[self layout];
|
||||
[self layoutDidFinish];
|
||||
}
|
||||
@@ -1539,9 +1540,20 @@ static NSInteger incrementIfFound(NSInteger i) {
|
||||
}
|
||||
_flags.isEnteringHierarchy = NO;
|
||||
|
||||
CALayer *layer = self.layer;
|
||||
if (!layer.contents) {
|
||||
|
||||
// If we don't have contents finished drawing by the time we are on screen, immediately add the placeholder (if it is enabled and we do have something to draw).
|
||||
if (self.contents == nil) {
|
||||
CALayer *layer = self.layer;
|
||||
[layer setNeedsDisplay];
|
||||
|
||||
if ([self _shouldHavePlaceholderLayer]) {
|
||||
[CATransaction begin];
|
||||
[CATransaction setDisableActions:YES];
|
||||
[self _setupPlaceholderLayerIfNeeded];
|
||||
_placeholderLayer.opacity = 1.0;
|
||||
[CATransaction commit];
|
||||
[self.layer addSublayer:_placeholderLayer];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1671,10 +1683,9 @@ static NSInteger incrementIfFound(NSInteger i) {
|
||||
|
||||
[_pendingDisplayNodes removeObject:node];
|
||||
|
||||
// only trampoline if there is a placeholder and nodes are done displaying
|
||||
if ([self _pendingDisplayNodesHaveFinished] && _placeholderLayer.superlayer) {
|
||||
if (_pendingDisplayNodes.count == 0 && _placeholderLayer.superlayer && ![self placeholderShouldPersist]) {
|
||||
void (^cleanupBlock)() = ^{
|
||||
[self _tearDownPlaceholderLayer];
|
||||
[_placeholderLayer removeFromSuperlayer];
|
||||
};
|
||||
|
||||
if (_placeholderFadeDuration > 0.0 && ASInterfaceStateIncludesVisible(self.interfaceState)) {
|
||||
@@ -1689,33 +1700,46 @@ static NSInteger incrementIfFound(NSInteger i) {
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method to check that all nodes that the current node is waiting to display are finished
|
||||
// Use this method to check to remove any placeholder layers
|
||||
- (BOOL)_pendingDisplayNodesHaveFinished
|
||||
{
|
||||
return _pendingDisplayNodes.count == 0;
|
||||
}
|
||||
|
||||
// Helper method to summarize whether or not the node run through the display process
|
||||
- (BOOL)__implementsDisplay
|
||||
{
|
||||
return _flags.implementsDrawRect || _flags.implementsImageDisplay || self.shouldRasterizeDescendants || _flags.implementsInstanceDrawRect || _flags.implementsInstanceImageDisplay;
|
||||
}
|
||||
|
||||
- (void)_setupPlaceholderLayer
|
||||
- (BOOL)placeholderShouldPersist
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
|
||||
_placeholderLayer = [CALayer layer];
|
||||
// do not set to CGFLOAT_MAX in the case that something needs to be overtop the placeholder
|
||||
_placeholderLayer.zPosition = 9999.0;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)_tearDownPlaceholderLayer
|
||||
- (BOOL)_shouldHavePlaceholderLayer
|
||||
{
|
||||
return (_placeholderEnabled && [self __implementsDisplay]);
|
||||
}
|
||||
|
||||
- (void)_setupPlaceholderLayerIfNeeded
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
|
||||
[_placeholderLayer removeFromSuperlayer];
|
||||
if (!_placeholderLayer) {
|
||||
_placeholderLayer = [CALayer layer];
|
||||
// do not set to CGFLOAT_MAX in the case that something needs to be overtop the placeholder
|
||||
_placeholderLayer.zPosition = 9999.0;
|
||||
}
|
||||
|
||||
if (_placeholderLayer.contents == nil) {
|
||||
if (!_placeholderImage) {
|
||||
_placeholderImage = [self placeholderImage];
|
||||
}
|
||||
if (_placeholderImage) {
|
||||
BOOL stretchable = !UIEdgeInsetsEqualToEdgeInsets(_placeholderImage.capInsets, UIEdgeInsetsZero);
|
||||
if (stretchable) {
|
||||
ASDisplayNodeSetupLayerContentsWithResizableImage(_placeholderLayer, _placeholderImage);
|
||||
} else {
|
||||
_placeholderLayer.contentsScale = self.contentsScale;
|
||||
_placeholderLayer.contents = (id)_placeholderImage.CGImage;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||
@@ -2252,26 +2276,6 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||
[self _pendingNodeWillDisplay:self];
|
||||
|
||||
[_supernode subnodeDisplayWillStart:self];
|
||||
|
||||
if (_placeholderImage && _placeholderLayer && self.layer.contents == nil) {
|
||||
[CATransaction begin];
|
||||
[CATransaction setDisableActions:YES];
|
||||
[self _setupPlaceholderLayerContents];
|
||||
_placeholderLayer.opacity = 1.0;
|
||||
[CATransaction commit];
|
||||
[self.layer addSublayer:_placeholderLayer];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_setupPlaceholderLayerContents
|
||||
{
|
||||
BOOL stretchable = !UIEdgeInsetsEqualToEdgeInsets(_placeholderImage.capInsets, UIEdgeInsetsZero);
|
||||
if (stretchable) {
|
||||
ASDisplayNodeSetupLayerContentsWithResizableImage(_placeholderLayer, _placeholderImage);
|
||||
} else {
|
||||
_placeholderLayer.contentsScale = self.contentsScale;
|
||||
_placeholderLayer.contents = (id)_placeholderImage.CGImage;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)displayDidFinish
|
||||
|
||||
Reference in New Issue
Block a user