Gradient rendering issue with alpha set to something other than one

Gradients with colors that have alpha are not rendered correctly anymore. I made a simple project to illustrate that. Just create Objective C project and paste this code inside the ViewController.

`#import <UIKit/UIKit.h>

@interface CustomView : UIView

@property (nonatomic, strong) NSArray<NSNumber *> *colorsArray; // The color components array

// Custom initializer that accepts an NSArray of color components

  • (instancetype)initWithFrame:(CGRect)frame colors:(NSArray<NSNumber *> *)colorsArray;

@end

@implementation CustomView

// Custom initializer

  • (instancetype)initWithFrame:(CGRect)frame colors:(NSArray<NSNumber *> *)colorsArray { self = [super initWithFrame:frame]; if (self) { _colorsArray = colorsArray; // Store the colors array } return self;

}

  • (void)drawRect:(CGRect)rect { // Get the current context CGContextRef context = UIGraphicsGetCurrentContext();

    // Convert NSArray to a C-style array of CGFloats size_t count = self.colorsArray.count; CGFloat colors[count]; for (size_t i = 0; i < count; i++) { colors[i] = [self.colorsArray[i] floatValue]; }

    // Create a color space CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    // Create the gradient with the passed colors CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, count / 4);

    // Define the start and end points of the gradient CGPoint startPoint = CGPointMake(rect.origin.x, rect.origin.y); CGPoint endPoint = CGPointMake(rect.origin.x, rect.origin.y + rect.size.height);

    // Draw the rectangle with the gradient CGContextSaveGState(context); CGContextAddRect(context, rect); CGContextClip(context); CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); CGContextRestoreGState(context);

    // Release resources CGGradientRelease(gradient); CGColorSpaceRelease(colorSpace);

}

@end

@interface ViewController : UIViewController @end

@implementation ViewController

  • (void)viewDidLoad { [super viewDidLoad];

    // Get the screen bounds CGRect screenBounds = [UIScreen mainScreen].bounds;

    // Define the size of each custom view CGFloat customViewWidth = screenBounds.size.width * 0.75; CGFloat customViewHeight = screenBounds.size.height * 0.75;

    // Define a dynamic set of colors for the first custom view (red to blue) NSArray<NSNumber *> *colorsArray1 = @[ @1.0, @0.0, @0.0, @1.0, // Red @0.0, @0.0, @1.0, @1.0 // Blue ];

    // TODO: This is the bug, there is no transparency NSNumber *alpha = @0.0;// this is the ***** bug **** // Define a dynamic set of colors for the second custom view (green to yellow) NSArray<NSNumber *> *colorsArray2 = @[ @0.0, @1.0, @0.0, alpha, // Green @1.0, @1.0, @0.0, @1.0 // Yellow ];

    // Calculate the position for the first view (centered horizontally and vertically, with slight offset) CGRect frame1 = CGRectMake((screenBounds.size.width - customViewWidth) / 2 - customViewWidth * 0.25, (screenBounds.size.height - customViewHeight) / 2 - customViewHeight * 0.25, customViewWidth, customViewHeight); CustomView *customView1 = [[CustomView alloc] initWithFrame:frame1 colors:colorsArray1];

    // Calculate the position for the second view (slightly shifted from the first view to partially overlap) CGRect frame2 = CGRectMake((screenBounds.size.width - customViewWidth) / 2 + customViewWidth * 0.25, (screenBounds.size.height - customViewHeight) / 2 + customViewHeight * 0.25, customViewWidth, customViewHeight); CustomView *customView2 = [[CustomView alloc] initWithFrame:frame2 colors:colorsArray2];

    // Set autoresizing so they adjust with the screen size customView1.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; customView2.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

    // Add the custom views to the view controller's view [self.view addSubview:customView1]; [self.view addSubview:customView2];

}

@end`

Answered by DTS Engineer in 810346022

Hey, thanks for providing some code. I was able to run that and reproduce the problem here on an iPhone 15 running iOS 18.0.1. Sorry, no solutions.

Our engineering teams need to investigate this issue, as resolution may involve changes to Apple's software. I'd greatly appreciate it if you could open a bug report, include a small Xcode project and some directions that can be used to reproduce the problem, and post the FB number here once you do.

Bug Reporting: How and Why? has tips on creating your bug report.

To write code you need to use three backticks, i.e.: ```

Because you used only one, the code isn't formatted correctly.

And, because you didn't edit your post within an hour to correct this, you would now have to add a new reply with the fixed code. You can do this if you like. I doubt many people will reformat your code themselves.


@interface CustomView : UIView

@property (nonatomic, strong) NSArray<NSNumber *> *colorsArray; // The color components array

// Custom initializer that accepts an NSArray of color components
- (instancetype)initWithFrame:(CGRect)frame colors:(NSArray<NSNumber *> *)colorsArray;

@end

@implementation CustomView

// Custom initializer
- (instancetype)initWithFrame:(CGRect)frame colors:(NSArray<NSNumber *> *)colorsArray {
    self = [super initWithFrame:frame];
    if (self) {
        _colorsArray = colorsArray; // Store the colors array
    }
    return self;
}

- (void)drawRect:(CGRect)rect {
    // Get the current context
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    // Convert NSArray to a C-style array of CGFloats
    size_t count = self.colorsArray.count;
    CGFloat colors[count];
    for (size_t i = 0; i < count; i++) {
        colors[i] = [self.colorsArray[i] floatValue];
    }
    
    // Create a color space
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    
    // Create the gradient with the passed colors
    CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, count / 4);
    
    // Define the start and end points of the gradient
    CGPoint startPoint = CGPointMake(rect.origin.x, rect.origin.y);
    CGPoint endPoint = CGPointMake(rect.origin.x, rect.origin.y + rect.size.height);
    
    // Draw the rectangle with the gradient
    CGContextSaveGState(context);
    CGContextAddRect(context, rect);
    CGContextClip(context);
    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
    CGContextRestoreGState(context);
    
    // Release resources
    CGGradientRelease(gradient);
    CGColorSpaceRelease(colorSpace);
}

@end

@interface ViewController : UIViewController
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // Get the screen bounds
    CGRect screenBounds = [UIScreen mainScreen].bounds;
    
    // Define the size of each custom view
    CGFloat customViewWidth = screenBounds.size.width * 0.75;
    CGFloat customViewHeight = screenBounds.size.height * 0.75;
    
    // Define a dynamic set of colors for the first custom view (red to blue)
    NSArray<NSNumber *> *colorsArray1 = @[
        @1.0, @0.0, @0.0, @1.0,  // Red
        @0.0, @0.0, @1.0, @1.0   // Blue
    ];
    
    // TODO: This is the bug, there is no transparency
    NSNumber *alpha = @0.0;// this is the ***** bug ****
    // Define a dynamic set of colors for the second custom view (green to yellow)
    NSArray<NSNumber *> *colorsArray2 = @[
        @0.0, @1.0, @0.0, alpha,  // Green
        @1.0, @1.0, @0.0, @1.0   // Yellow
    ];
    
    // Calculate the position for the first view (centered horizontally and vertically, with slight offset)
    CGRect frame1 = CGRectMake((screenBounds.size.width - customViewWidth) / 2 - customViewWidth * 0.25,
                               (screenBounds.size.height - customViewHeight) / 2 - customViewHeight * 0.25,
                               customViewWidth, customViewHeight);
    CustomView *customView1 = [[CustomView alloc] initWithFrame:frame1 colors:colorsArray1];
    
    // Calculate the position for the second view (slightly shifted from the first view to partially overlap)
    CGRect frame2 = CGRectMake((screenBounds.size.width - customViewWidth) / 2 + customViewWidth * 0.25,
                               (screenBounds.size.height - customViewHeight) / 2 + customViewHeight * 0.25,
                               customViewWidth, customViewHeight);
    CustomView *customView2 = [[CustomView alloc] initWithFrame:frame2 colors:colorsArray2];
    
    // Set autoresizing so they adjust with the screen size
    customView1.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    customView2.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    
    // Add the custom views to the view controller's view
    [self.view addSubview:customView1];
    [self.view addSubview:customView2];
}

@end

Hey, thanks for providing some code. I was able to run that and reproduce the problem here on an iPhone 15 running iOS 18.0.1. Sorry, no solutions.

Our engineering teams need to investigate this issue, as resolution may involve changes to Apple's software. I'd greatly appreciate it if you could open a bug report, include a small Xcode project and some directions that can be used to reproduce the problem, and post the FB number here once you do.

Bug Reporting: How and Why? has tips on creating your bug report.

Gradient rendering issue with alpha set to something other than one
 
 
Q