Creating a UIImage from a UIColor to use as a background image for UIButton [duplicate]
Asked Answered
E

7

160

I'm creating a colored image like this:

CGRect rect = CGRectMake(0, 0, 1, 1);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context,
                                   [[UIColor redColor] CGColor]);
//  [[UIColor colorWithRed:222./255 green:227./255 blue: 229./255 alpha:1] CGColor]) ;
CGContextFillRect(context, rect);
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

and then use it as the background image of a button:

[resultButton setBackgroundImage:img forState:UIControlStateNormal];

This works great using the redColor, however I want to use an RGB color (as shown in the commented line). When I use the RGB color, the buttons background isn't changed.

What am I missing?

Eda answered 27/6, 2011 at 17:14 Comment(4)
If you are just setting a background color for the button, why wouldnt you simply use the setBackgroundColor: method?Altruist
Setting the backgroundColor only changes the outside of the rounded corners, but not the actual area of the button itself.Eda
Your code works fine on my ENV, xcode501,iPhoneSimulator703, look carefully, the button is most likely a button with light white image.Welfarism
This should be updated to use UIGraphicsImageRendererBriones
C
150

I created a category around UIButton to be able to set the background color of the button and set the state. You might find this useful.

@implementation  UIButton (ButtonMagic)

- (void)setBackgroundColor:(UIColor *)backgroundColor forState:(UIControlState)state {
    [self setBackgroundImage:[UIButton imageFromColor:backgroundColor] forState:state];
}

+ (UIImage *)imageFromColor:(UIColor *)color {
    CGRect rect = CGRectMake(0, 0, 1, 1);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

This will be part of a set of helper categories I'm open sourcing this month.

Swift 2.2

extension UIImage {
static func fromColor(color: UIColor) -> UIImage {
    let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
    UIGraphicsBeginImageContext(rect.size)
    let context = UIGraphicsGetCurrentContext()
    CGContextSetFillColorWithColor(context, color.CGColor)
    CGContextFillRect(context, rect)
    let img = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return img
  }
}

Swift 3.0

extension UIImage {
    static func from(color: UIColor) -> UIImage {
        let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
        UIGraphicsBeginImageContext(rect.size)
        let context = UIGraphicsGetCurrentContext()
        context!.setFillColor(color.cgColor)
        context!.fill(rect)
        let img = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return img!
    }
}

Use as

let img = UIImage.from(color: .black)
Collective answered 7/7, 2014 at 16:43 Comment(3)
Rather than being a category on UIButton, though now in Swift we are on extensions rather than categories, don't you think it would be best to have an extension on UIImage for the initializer rather than UIButtonTanning
Can I use this to create an image of certain dimensions? How do I do it? Sorry if my question, appears very naive.. :-/Fieldsman
If you're just talking about creating a rectangle with specific dimensions then change the width and height to whatever you'd like it to be.Collective
P
14

Xamarin.iOS solution

 public UIImage CreateImageFromColor()
 {
     var imageSize = new CGSize(30, 30);
     var imageSizeRectF = new CGRect(0, 0, 30, 30);
     UIGraphics.BeginImageContextWithOptions(imageSize, false, 0);
     var context = UIGraphics.GetCurrentContext();
     var red = new CGColor(255, 0, 0);
     context.SetFillColor(red);
     context.FillRect(imageSizeRectF);
     var image = UIGraphics.GetImageFromCurrentImageContext();
     UIGraphics.EndImageContext();
     return image;
 }
Pronunciation answered 12/4, 2015 at 2:28 Comment(1)
This is working for me with C# Xamarin. Any insight on how to make this UIImage rounded?Kenzie
B
6

Are you using ARC? The problem here is that you don't have a reference to the UIColor object that you're trying to apply; the CGColor is backed by that UIColor, but ARC will deallocate the UIColor before you have a chance to use the CGColor.

The clearest solution is to have a local variable pointing to your UIColor with the objc_precise_lifetime attribute.

You can read more about this exact case on this article about UIColor and short ARC lifetimes or get more details about the objc_precise_lifetime attribute.

Bobbiebobbin answered 27/6, 2012 at 11:57 Comment(3)
A valid observation, but that would result in a crash, which it sounds like the OP hasn't observed.Macri
Not necessarily; it depends on the details of how CGColor and CGContextFillRect interact, not to mention other details that might change from OS version to OS version. Certainly it could be something else, but since the code is broken as written (if ARC is being used) it's a first step at least.Bobbiebobbin
My code was from the pre-ARC days.Eda
S
5

Add the dots to all values:

[[UIColor colorWithRed:222./255. green:227./255. blue: 229./255. alpha:1] CGColor]) ;

Otherwise, you are dividing float by int.

Scattering answered 23/11, 2012 at 16:45 Comment(1)
Not true - the integer argument is automatically promoted to a floating point value (double in this case) before the expression is evaluated, because the left hand operand is of type double. See this answer for a detailed explanationEads
T
4

I suppose that 255 in 227./255 is perceived as an integer and divide is always return 0

Teutonism answered 27/6, 2011 at 19:21 Comment(1)
Thanks for the idea (also suggested by someone who deleted his answer). The division works fine as it is, even when building the color from properly set floats (dummy vars declared and their value checked in the debugger), setting the background image does not do anything.Eda
T
4

Your code works fine. You can verify the RGB colors with Iconfactory's xScope. Just compare it to [UIColor whiteColor].

Trepang answered 28/6, 2011 at 11:44 Comment(0)
N
4
CGContextSetFillColorWithColor(context,[[UIColor colorWithRed:(255/255.f) green:(0/255.f) blue: (0/255.f) alpha:1] CGColor]);
Nutritious answered 27/6, 2012 at 11:21 Comment(1)
Not sure what you mean with your answer .. I was not trying to replace colorRed with RGB values, but use my own values instead - which doesn't seem to work.Eda

© 2022 - 2024 — McMap. All rights reserved.