How can I set a button background color on iPhone?

后端 未结 18 1986
予麋鹿
予麋鹿 2020-11-30 20:22

How can I set a custom background color of a button?

Interface Builder doesn\'t seem to have an interface to do this.

Is it only available programmatically

相关标签:
18条回答
  • 2020-11-30 21:05

    Here's a variation on @user200212's solution (http://stackoverflow.com/a/8547424). It uses the UIBezierCurve class to fill the button and draw a 1px black border around it:

    UIButton+ColoredBackground.h

    //  UIButton+ColoredBackground.h
    
    #import <UIKit/UIKit.h>
    
    @interface UIButton (ColoredBackground)
    
    - (void)setBackgroundColor:(UIColor *)backgroundColor forState:(UIControlState)state;
    + (UIColor *) silverColor;
    
    @end
    

    UIButton+ColoredBackground.m

    //  UIButton+ColoredBackground.m
    #import "UIButton+ColoredBackground.h"
    #import <QuartzCore/QuartzCore.h>
    
    @implementation UIButton (UIButton_ColoredBackground)
    
    - (void)setBackgroundColor:(UIColor *)backgroundColor forState:(UIControlState)state{
    
        CGSize gcSize = self.bounds.size;
        UIGraphicsBeginImageContext(gcSize);
    
        // Create a Bezier Path around the button, and fill it with the background color
        UIBezierPath *outsideEdge = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:8.0f];
        [backgroundColor setFill];
        [[UIColor blackColor] setStroke];
        outsideEdge.lineWidth = 1.0;
        [outsideEdge fill];
        [outsideEdge stroke];
    
        // Create the background image
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();    
    
        UIGraphicsEndImageContext(); 
    
        // Set image as button's background image for the given state
        [self setBackgroundImage:image forState:state];
    
        // Ensure rounded button
        self.clipsToBounds = YES;
        self.layer.cornerRadius = 8.0;
    }
    
    @end
    

    Usage:

    [myButton setBackgroundImageByColor:[UIColor greenColor] forState:UIControlStateNormal];
    
    0 讨论(0)
  • 2020-11-30 21:06

    i have a little modified the code version of @Patch. The problem for me was that the old version stretched the corner radius kind of dirty when switching from portrait to landscape mode. So i made this version use stretchableImageWithLeftCapWidth:topCapHeight Method.

    #import "UIButton+ColoredBackground.h"
    #import <QuartzCore/QuartzCore.h>
    
    #define kCornerRadius 8.0f
    #define kStrokeColor [UIColor blackColor]
    #define kStrokeWidth 1.0f
    
    @implementation UIButton (ColoredBackground)
    
    - (void)setBackgroundImageByColor:(UIColor *)backgroundColor forState:(UIControlState)state{
    
    
    CGSize gcSize = CGSizeMake(2*kCornerRadius +1, self.bounds.size.height);
    UIGraphicsBeginImageContext(gcSize);
    CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeOverlay);
    
    
    
    CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
    
    UIColor *gradientStart = [UIColor colorWithRed:0.80 green:0.80 blue:0.80 alpha:0.2];
    UIColor * gradientEnd = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.2];
    NSArray *colors = [NSArray arrayWithObjects:(id)gradientStart.CGColor, (id)gradientEnd.CGColor, nil];
    CGFloat locations[2] = { 0.0f, 1.0f };
    CGGradientRef _gradient = CGGradientCreateWithColors(rgb, (__bridge CFArrayRef)colors, locations);
    CGColorSpaceRelease(rgb);
    CGContextDrawLinearGradient(UIGraphicsGetCurrentContext(), _gradient, CGPointMake(0.0, kStrokeWidth), CGPointMake(0.0, self.bounds.size.height-kStrokeWidth), 0);
    
    UIBezierPath *outsideEdge = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0.0, 0.0, gcSize.width, gcSize.height) cornerRadius:kCornerRadius];
    [backgroundColor setFill];
    [kStrokeColor setStroke];
    outsideEdge.lineWidth = kStrokeWidth;
    [outsideEdge stroke];
    [outsideEdge fill];
    
    // Create the background image
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();    
    UIGraphicsEndImageContext(); 
    
    // Set image as button's background image (stretchable) for the given state
    [self setBackgroundImage:[image stretchableImageWithLeftCapWidth:kCornerRadius topCapHeight:0.0] forState:state];
    
    // Ensure rounded button
    self.clipsToBounds = YES;
    self.layer.cornerRadius = kCornerRadius;
    
    
    
    }
    
    @end
    

    The usage didn't changed. It looks clearer now on the edges, and i also aded a gradient to make more plastic. but you can remove this as well.

    0 讨论(0)
  • 2020-11-30 21:06

    i did it as follows to create button like system delete button as in uitableview

    
    UIButton *h=[[UIButton  alloc]init];
    [[h layer] setCornerRadius:8.0f];
    [[h layer] setMasksToBounds:YES];
    [[h layer] setBorderWidth:1.0f];
    CAGradientLayer *gradientLayer = [[CAGradientLayer alloc] init];
    [gradientLayer setBounds:[h bounds]];
    [gradientLayer setPosition:CGPointMake([h bounds].size.width/2, [h bounds].size.height/2)];
    [gradientLayer setColors:[NSArray arrayWithObjects:
    (id)[[UIColor darkGrayColor]CGColor],(id)[[UIColor blackColor] CGColor], nil]];
    [[h layer] insertSublayer:gradientLayer atIndex:0];
    

    release all objects and import QuartzCore/QuartzCore.h and add this framework to your project.

    0 讨论(0)
  • 2020-11-30 21:07

    I read your question to require (as I do) a programmatic way to set button color. It's a glaring omission from the UIKit, and I couldn't get the undocumented UIGlassButton to work.

    I've solved this with a single segment UISegmentedControl, which allows you to set the tintColor:

    UISegmentedControl * btn = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:name]];
    btn.momentary = YES;
    btn.segmentedControlStyle = UISegmentedControlStyleBar;
    btn.tintColor = color;
    [btn addTarget:self action:@selector(action:) forControlEvents:UIControlEventValueChanged];
    

    Note please that the momentary and segmentedControlStyle properties do matter, and that an image can be used instead of a NSString * name.

    A stretchable image with end caps works fine if you can use a finite set of canned images, but that doesn't fit the requirement! E.g.,

    buttonImage   = [[UIImage imageNamed:@"button.png"] stretchableImageWithLeftCapWidth:26 topCapHeight:16];
    
    0 讨论(0)
  • 2020-11-30 21:07

    To keep the button rounded, what about using

    view.layer.cornerRadius = 8;
    

    described here

    How do I create a round cornered UILabel on the iPhone?

    0 讨论(0)
  • 2020-11-30 21:10

    Building further on @Denny1989 I've solved a problem getting errors (invalid context 0x0) when setting up the button in viewDidLoad. The button needs to be laid out before it has a size and thus cannot be depended on until after the view appears. This category adds a color for UIControlStateNormal. If other control states are necessary for your app you need to add them similarly to the category.

    //  UIButton+ColoredBackground.h
    
    #import <UIKit/UIKit.h>
    
    @interface UIButton (ColoredBackground)
    
    @property (nonatomic, retain) UIColor *buttonColorNormal;
    
    @property (nonatomic, retain) NSNumber *madeBackgroundImages;
    
    - (void)setBackgroundColor:(UIColor *)backgroundColor forState:(UIControlState)state;
    
    - (void)drawRect:(CGRect)rect;
    
    - (void)awakeFromNib;
    
    @end
    

    and

    //  UIButton+ColoredBackground.m
    
    #import "UIButton+ColoredBackground.h"
    #import <QuartzCore/QuartzCore.h>
    #import <objc/runtime.h>
    
    #define kCornerRadius 8.0f
    #define kStrokeColor [UIColor darkGrayColor]
    #define kStrokeWidth 1.0f
    
    
    
    @implementation UIButton (ColoredBackground)
    
    static char UIB_ButtonColorNormal_KEY;
    static char UIB_MadeBackgroundImages_KEY;
    
    @dynamic buttonColorNormal;
    
    -(void)setButtonColorNormal:(NSObject *)buttonColorNormal
    {
        objc_setAssociatedObject(self, &UIB_ButtonColorNormal_KEY, buttonColorNormal, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    -(NSObject*)buttonColorNormal
    {
        return (NSObject*)objc_getAssociatedObject(self, &UIB_ButtonColorNormal_KEY);
    }
    
    @dynamic madeBackgroundImages;
    
    -(void)setMadeBackgroundImages:(NSObject *)madeBackgroundImages
    {
        objc_setAssociatedObject(self, &UIB_MadeBackgroundImages_KEY, madeBackgroundImages, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    -(NSObject*)madeBackgroundImages
    {
        return (NSObject*)objc_getAssociatedObject(self, &UIB_MadeBackgroundImages_KEY);
    }
    - (void)awakeFromNib {
        [self setMadeBackgroundImages:[NSNumber numberWithBool:FALSE]];
        [super awakeFromNib];
    }
    
    - (void)drawRect:(CGRect)rect {
        // if background images were not created from color do so here
        // if self.buttonColorNormal is not set behaves like normal button
        if ((self.buttonColorNormal)&&(![[self madeBackgroundImages] boolValue])) {
            [self setBackgroundColor:[self buttonColorNormal] forState:UIControlStateNormal];
            [self setMadeBackgroundImages:[NSNumber numberWithBool:TRUE]];
        }
        [super drawRect:rect];
    }
    
    - (void)setBackgroundColor:(UIColor *)backgroundColor forState:(UIControlState)state {
    
        gcSize = CGSizeMake(2*kCornerRadius +1, self.bounds.size.height);
        UIGraphicsBeginImageContext(gcSize);
    
        CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
    
        UIColor *gradientStart = [UIColor colorWithRed:0.80 green:0.80 blue:0.80 alpha:0.2];
        UIColor * gradientEnd = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.5];
        NSArray *colors = [NSArray arrayWithObjects:(id)gradientStart.CGColor, (id)gradientEnd.CGColor, nil];
        CGFloat locations[2] = { 0.0f, 1.0f };
        CGGradientRef _gradient = CGGradientCreateWithColors(rgb, (__bridge CFArrayRef)colors, locations);
        CGColorSpaceRelease(rgb);
        CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeOverlay);
        CGContextDrawLinearGradient(UIGraphicsGetCurrentContext(), _gradient, CGPointMake(0.0, kStrokeWidth), CGPointMake(0.0, self.bounds.size.height-kStrokeWidth), 0);
    
        UIBezierPath *outsideEdge = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0.0, 0.0, gcSize.width, gcSize.height) cornerRadius:kCornerRadius];
        [backgroundColor setFill];
        [kStrokeColor setStroke];
        outsideEdge.lineWidth = kStrokeWidth;
        [outsideEdge stroke];
        [outsideEdge fill];
        CFRelease(_gradient);
    
        // Create the background image
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        // Set image as button's background image (stretchable) for the given state
        [self setBackgroundImage:[image stretchableImageWithLeftCapWidth:kCornerRadius topCapHeight:0.0] forState:state];
    
        // Ensure rounded button
        self.clipsToBounds = YES;
        self.layer.cornerRadius = kCornerRadius;
    
        // add colored border
        self.layer.borderColor = kStrokeColor.CGColor;
        self.layer.borderWidth = kStrokeWidth;
    }
    
    @end
    

    usage

    - (void)viewDidLoad
    {
            [myButton setButtonColorNormal:[UIColor redColor]];
    }
    

    Be sure to make the button type custom or drawRect may not be called.

    0 讨论(0)
提交回复
热议问题