CALayer displaying wrong SFSymbol image for light / dark mode

310 views Asked by At

My first SO question so here goes...

I'm very familiar with working with CALayer and its variants but this one has me stumped.

Let's start with the code ( yes, I'm working in Objective-C )...

- (void)setup
{
    // a basic setup method, called from layoutSubviews
    
    if( self.needsSetup )
    {
        self.needsSetup = NO;
        
        if( !_infoTextLayer )
        {
            
            _infoTextLayer = [self makeLowerTextLayer];
            
            [self.layer addSublayer: _infoTextLayer];
            
            
            CGFloat midX, midY;
            
            midX = CGRectGetMidX( self.layer.bounds );
            midY = CGRectGetMidY( self.layer.bounds );
            
            CGRect  itlBounds   = _infoTextLayer.bounds; // our reference for size
            
            CGRect  frameRect   = CGRectMake( 0.0f, 0.0f, itlBounds.size.height, itlBounds.size.height);
            CGPoint pos         = CGPointMake( midX, midY );

            CALayer *newLayer   = [self makeBasicLayer: @"infoSymbol" : frameRect : pos];
            
            newLayer.delegate   = self;

            _infoLayer          = newLayer;
            
            [_infoLayer setNeedsDisplay];
            
            [self.layer addSublayer: newLayer];
            
        }
    }
}

// a simple utility method...
- (CALayer *)makeBasicLayer:  (NSString *) name :(CGRect) frame : (CGPoint) position
{
    CALayer *newLayer = [CALayer layer];
    
    newLayer.rasterizationScale = [[UIScreen mainScreen] scale];
    newLayer.contentsScale      = [[UIScreen mainScreen] scale];
    
    newLayer.name               = name;
    newLayer.frame              = frame;
    newLayer.position           = position;
    newLayer.contentsGravity    = kCAGravityResize;
    
    return newLayer;
}

// delegate method
- (void)displayLayer:(CALayer *)layer
{
    if( [layer.name isEqualToString: @"infoSymbol"] ) // make sure we're changing the correct layer
    {
        UITraitCollection   *tc = self.traitCollection;
        
        // just to give us a little more visual feedback...
        if( tc.userInterfaceStyle == UIUserInterfaceStyleDark )
        {
            layer.backgroundColor = [UIColor systemYellowColor].CGColor;
        }
        else
        {
            layer.backgroundColor = [UIColor whiteColor].CGColor;

        }
        
        // normally I'd set the layers contents like this...
        //layer.contents  = CFBridgingRelease([UIImage systemImageNamed: @"info.circle" compatibleWithTraitCollection: tc].CGImage);
        
        // but for the sake of this question to SO...
        UIImage *sysImage   = [UIImage systemImageNamed: @"info.circle" compatibleWithTraitCollection: tc];
        
        layer.contents  = CFBridgingRelease( sysImage.CGImage );
        

        // doing this will return the system image with the white color but when it is displayed by
        // the CALayer the on screen image is a black ( default UIUserInterfaceStyleLight ) image
//        layer.contents          = CFBridgingRelease([[UIImage systemImageNamed: @"info.circle"] imageWithTintColor: [UIColor whiteColor]].CGImage);
//
    }
}

In traitCollectionDidChange I again call [self.infoLayer setNeedsDisplay]; to trigger the delegate method displayLayer, which gets called as expected but the returned image is always the image for light mode.

I get the same behavior weather running on the simulator or a real device ( iPhone or iPad ).

These are screenshots from the simulator ( 11 Pro, iOS 14.5 )

light mode screen shot

dark mode screen shot

Am I missing something here ?

0

There are 0 answers