1

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 ?

The Cooper
  • 11
  • 2
  • Did you find an answer? – Nikolay Sohryakov Sep 20 '21 at 12:29
  • @NikolaySohryakov I did find a work around, but I've been away from this particular issue for a couple of months on another project so I don't have it off the top of my head... give me a couple of days to track it down and I'll post an update with code snippets – The Cooper Sep 21 '21 at 21:50
  • @NikolaySohryakov well actually, I do have the work around off the top of my head. But to do justice to you and anyone else that reads this an edited update would be the best – The Cooper Sep 21 '21 at 23:06
  • 1
    So I was able to track it down and the reason for this behaviour is that CGImage does not apply tint color automatically. This needs to be done manually or this can be done with a mask workaround: `mask = maskLayer // created from image` `backgroundColor = R.color.slider.filled()?.cgColor // color to be applied` – Nikolay Sohryakov Sep 22 '21 at 10:48
  • The previous comments lead me to https://stackoverflow.com/a/28108612/4570376 which covers the same issue I believe – Bugmeister Jun 23 '23 at 00:10

0 Answers0