更改UIButton的背景颜色是否可行?

107

这个问题让我不知所措。

在 iPhone 的 Cocoa 开发中,是否有可能改变 UIButton 的背景颜色?我已经尝试过设置背景颜色,但它只会改变圆角。似乎 setBackgroundColor: 是唯一可用于此类操作的方法。

[random setBackgroundColor:[UIColor blueColor]];
[random.titleLabel setBackgroundColor:[UIColor blueColor]];

这是 https://dev59.com/FHRC5IYBdhLWcg3wOOT1 的副本,如何在 iPhone 上设置按钮背景颜色。 - Brad Larson
我在之前的帖子中解决了这个问题,请查看链接:动态更改UIButton的边框或背景 - IMMORTAL
在这里可以找到很好的教程和示例代码:http://www.cimgf.com/2010/01/28/fun-with-uibuttons-and-core-animation-layers/ - Shamsudheen TK
这是针对iOS7之前的 - 在iOS7中,设置背景颜色可以按预期工作,不需要下面的代码。 - brainray
请查看此帖子 https://somethingaboutios.wordpress.com/2016/02/09/uibutton-backgroundcolor-for-uicontrolstateselected/ - Gabriel.Massana
17个回答

161

这可以通过编程来实现,制作一个副本:

loginButton = [UIButton buttonWithType:UIButtonTypeCustom];
[loginButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
loginButton.backgroundColor = [UIColor whiteColor];
loginButton.layer.borderColor = [UIColor blackColor].CGColor;
loginButton.layer.borderWidth = 0.5f;
loginButton.layer.cornerRadius = 10.0f;

编辑:当然,您需要 #import <QuartzCore/QuartzCore.h>

编辑:对于所有新读者,您还应该考虑添加为“另一个可能性”的几个选项。供您考虑。

由于这是一个旧答案,我强烈建议阅读评论以进行故障排除。


4
甜!在我找到的所有解决方案中,我选择了这个。澄清一点,制作“复制品”意味着使用石英来绘制圆角矩形的自定义按钮,而不是使用RoundedRect类型的按钮。起初,我以为它意味着以不同颜色制作圆角矩形的副本,以模拟更改背景颜色。 - daver
1
完美地工作了,对提问者来说是最佳答案。感谢分享。 - Bram
我没有得到预期的结果,因为背景图片变成绿色并立即恢复原来的颜色。我该如何永久更改颜色,并仅在需要时删除?谢谢。 - mmm
1
@Polly:抱歉没有早点看到你的评论,但如果你还感兴趣,这就是我最终做的事情:子类化UIButton并覆盖drawRect:使用一些UIBezierPaths绘制圆角矩形。绘制完成后,使用CGGradientCreateWithColorComponents()填充渐变。这个函数的一个参数是一个由四个浮点数组成的4元素数组(对应R、G、B和alpha)。我定义了两个颜色数组,分别对应于每个状态,并在drawRect中根据按钮状态选择适当的颜色数组。 - daver
需要注意的是,layer.borderColor需要使用CGColor而不是UIColor!因此,您不能像layer.cornerRadius和layer.borderWidth那样将其添加为身份检查器中的动态属性。 - RndmTsk
显示剩余6条评论

60

我有一种不同的方法,

[btFind setTitle:NSLocalizedString(@"Find", @"") forState:UIControlStateNormal];    
[btFind setBackgroundImage:[CommonUIUtility imageFromColor:[UIColor cyanColor]] 
        forState:UIControlStateNormal];
btFind.layer.cornerRadius = 8.0;
btFind.layer.masksToBounds = YES;
btFind.layer.borderColor = [UIColor lightGrayColor].CGColor;
btFind.layer.borderWidth = 1;

来自CommonUIUtility,

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

别忘了 #import <QuartzCore/QuartzCore.h>


2
不错。我发现我需要添加 btFind.layer.borderWidth = 1; - DefenestrationDay
我喜欢这个解决方案,但目前无法使用它。我遇到了一个错误,因为找不到“CommonUIUtility”。谷歌只给我一些关于eclipse的东西,但我猜它应该在QuartzCore中吧? 有什么想法吗? - Stephan
不,那是一个用户定义的类,用于在应用程序中执行常见的UI操作。您需要在自己的类中编写imageFromColor方法。 - karim
这比应该的要难得多。感谢您提供了一个很棒的解决方案。 - Adam Waite
1
这似乎是UIButton上的一个类别方法:setBackgroundColor:(UIColor *) forState:(UIControlState) - EthanB
3
很傻的是我们现在用的是iOS 7,但这仍然是添加背景颜色最清晰的方法。 - dmur

32
我假设你正在谈论拥有 UIButtonTypeRoundedRect 类型的 UIButton? 你无法更改其背景颜色。当你尝试更改其背景颜色时,实际上是在更改按钮所绘制的矩形的颜色(通常是透明的)。 因此,有两种方法可行。一种是子类化 UIButton 并覆盖其 -drawRect: 方法,另一种是为不同的按钮状态创建图像(这样做是完全可以的)。
如果你在 Interface Builder 中设置背景图像,应该注意到 IB 不支持设置按钮可能具有的所有状态的图像,因此我建议像这样在代码中设置图像:
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeCustom];
[myButton setBackgroundImage:[UIImage imageNamed:@"normal.png"] forState:UIControlStateNormal];
[myButton setBackgroundImage:[UIImage imageNamed:@"disabled.png"] forState:UIControlStateDisabled];
[myButton setBackgroundImage:[UIImage imageNamed:@"selected.png"] forState:UIControlStateSelected];
[myButton setBackgroundImage:[UIImage imageNamed:@"higligted.png"] forState:UIControlStateHighlighted];
[myButton setBackgroundImage:[UIImage imageNamed:@"highlighted+selected.png"] forState:(UIControlStateHighlighted | UIControlStateSelected)];

最后一行显示如何为选定和高亮状态设置图像(这是IB无法设置的状态)。 如果您的按钮不需要选定状态,则不需要选定图像(第4和6行)。


谢谢解释。我有一个快速的问题。如果我要重写drawrect方法,那么我想这将涉及使用绘图库?类似于以编程方式绘制一个圆角矩形并填充它的颜色? - dubbeat
2
我刚刚在谷歌上搜索了“iphone drawrect round corners”,并找到了这个链接:http://iphonedevelopment.blogspot.com/2008/11/creating-transparent-uiviews-rounded.html查看drawrect方法,可以找到如何绘制圆角矩形的示例。您可以使用CGContextSetFillColorWithColorCGContextFillPath来填充由CGContextAddArcToPoint绘制的路径。 - stigi
2
+50 分,指出位掩码在控制状态方面的潜力,即:forState:(UIControlStateHighlighted | UIControlStateSelected)。干杯。 - NSTJ

29

另一个可能的方法:

  1. 在Interface Builder中创建一个UIButton。
  2. 将其类型设置为“Custom”
  3. 现在,在IB中可以更改背景颜色

然而,按钮是正方形的,这不是我们想要的。创建一个IBOutlet,引用这个按钮,并将以下内容添加到viewDidLoad方法中:

[buttonOutlet.layer setCornerRadius:7.0f];
[buttonOutlet.layer setClipToBounds:YES];

不要忘记导入QuartzCore.h


7
好的,谢谢!我不确定是因为我使用的iOS版本(5.1)才导致setClipToBounds不可用。相反,我使用了buttonOutlet.layer.masksToBounds = TRUE; - iforce2d
当我添加这段代码时,显示出一个圆角矩形,但当我点击它时,按钮没有逆转高亮。发生了什么? - Will
这种方法的问题在于,您无法为按钮的高亮状态设置背景颜色。 - ch3rryc0ke

17

继承UIButton并重写setHighlighted和setSelected方法。

-(void) setHighlighted:(BOOL)highlighted {

  if(highlighted) {
    self.backgroundColor = [self.mainColor darkerShade];
  } else {
    self.backgroundColor = self.mainColor;
  }
  [super setHighlighted:highlighted];
}

-(void) setSelected:(BOOL)selected {

  if(selected) {
    self.backgroundColor = [self.mainColor darkerShade];
  } else {
    self.backgroundColor = self.mainColor;
  }
  [super setSelected:selected];
}

我的darkerShade方法是在一个UIColor类别中实现的,如下所示:

-(UIColor*) darkerShade {

  float red, green, blue, alpha;
  [self getRed:&red green:&green blue:&blue alpha:&alpha];

  double multiplier = 0.8f;
  return [UIColor colorWithRed:red * multiplier green:green * multiplier blue:blue*multiplier alpha:alpha];
}

7

彩色UIButton

如果您不想使用图像并且希望它看起来与圆角矩形样式完全相同,请尝试以下方法。只需将UIView放在UIButton上方,具有相同的框架和自动调整大小掩码,将alpha设置为0.3,并将背景设置为颜色。然后使用下面的片段从着色覆盖视图中剪切圆角。此外,在IB上取消选中UIView上的“用户交互已启用”复选框,以允许触摸事件向下级联到下面的UIButton。

一个副作用是您的文本也会被着色。

#import <QuartzCore/QuartzCore.h>

colorizeOverlayView.layer.cornerRadius = 10.0f;
colorizeOverlayView.layer.masksToBounds = YES;

7

另一种可能性(我认为是最好和最美的):

在Interface Builder中创建一个具有2个片段的UISegmentedControl,并将其设置为所需的背景颜色。将类型设置为“bar”。然后,将其更改为仅具有一个片段。Interface builder不接受一个片段,因此您必须通过编程方式完成。

因此,在此按钮上创建一个IBOutlet,并将其添加到视图的viewDidLoad中:

[segmentedButton removeSegmentAtIndex:1 animated:NO];

现在你有一个带有指定背景颜色的漂亮光泽彩色按钮。 对于操作,请使用“值更改”事件。 (我在http://chris-software.com/index.php/2009/05/13/creating-a-nice-glass-buttons/上找到了这个。感谢Chris!)

5

我非常肯定你不能直接更改UIButton的背景颜色。相反,你必须自己更改背景图片,我认为这很麻烦。我很惊讶我不得不这样做。

如果我错了或者有更好的方法而不需要设置背景图片,请告诉我。

[random setBackgroundImage:[UIImage imageNamed:@"toggleoff.png"] forState:UIControlStateNormal];
    [random setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal];


[random setBackgroundImage:[UIImage imageNamed:@"toggleon.png"] forState:UIControlStateNormal];
    [random setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];

5
你说得很对。这确实是一件麻烦事,应该只需要几分钟的时间就能完成,而不必费力去制作图片。如果你的按钮是圆形的话,这样做就更加困难了...真是太麻烦了。 - Henley

2
根据@EthanB的建议和@karim创建一个后填充矩形,我刚刚为UIButton创建了一个类别以实现此功能。 只需添加类别代码:https://github.com/zmonteca/UIButton-PLColor 用法:
[button setBackgroundColor:uiTextColor forState:UIControlStateDisabled];

可选的状态使用:

UIControlStateNormal
UIControlStateHighlighted
UIControlStateDisabled
UIControlStateSelected

2

你也可以向按钮中添加一个CALayer,使用这个可以做很多事情,包括颜色叠加,此示例使用纯色图层,你还可以轻松地渐变颜色。请注意,添加的图层会遮挡下面的图层。

+(void)makeButtonColored:(UIButton*)button color1:(UIColor*) color
{

    CALayer *layer = button.layer;
    layer.cornerRadius = 8.0f;
    layer.masksToBounds = YES;
    layer.borderWidth = 4.0f;
    layer.opacity = .3;//
    layer.borderColor = [UIColor colorWithWhite:0.4f alpha:0.2f].CGColor;

    CAGradientLayer *colorLayer = [CAGradientLayer layer];
    colorLayer.cornerRadius = 8.0f;
    colorLayer.frame = button.layer.bounds;
    //set gradient colors
    colorLayer.colors = [NSArray arrayWithObjects:
                         (id) color.CGColor,
                         (id) color.CGColor,
                         nil];

    //set gradient locations
    colorLayer.locations = [NSArray arrayWithObjects:
                            [NSNumber numberWithFloat:0.0f],
                            [NSNumber numberWithFloat:1.0f],
                            nil];


    [button.layer addSublayer:colorLayer];

}

太棒了!!!!!但是不能对同一个按钮多次调用。虽然可以,但是会不断添加新的层。 - Valeriy Van
@StanJames:对代码的修改应该通过评论(或者如果合适的话,通过你自己的答案)来建议。 - mafso

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接