带有渐变的UIButton,圆angular,边框和阴影

在网站上有一些类似的问题,但我正在寻找一些具体的,稍有不同的东西。

我遵循这里给出的方向: http : //www.cimgf.com/2010/01/28/fun-with-uibuttons-and-core-animation-layers/以子类UIButton为了创build一个generics类,我可以指定渐变颜色,而不是尝试使用静态图像。

我碰到一个问题,button层上的setMasksToBounds将允许A)显示阴影,但也允许渐变图层显示超出圆angular或B)渐变图层剪辑到圆angular,但不允许显示阴影

我对这个问题的解决方法看起来很笨重(尽pipe有效),我想看看是否有人知道一个更好和/或更简洁的方法来完成同样的事情。 这是我的代码:

CSGradientButton.h

#import <UIKit/UIKit.h> @interface CSGradientButton : UIButton { UIColor *_highColor; UIColor *_lowColor; CAGradientLayer *gradientLayer; CALayer *wrapperLayer; CGColorRef _borderColor; } @property (nonatomic, retain) UIColor *_highColor; @property (nonatomic, retain) UIColor *_lowColor; @property (nonatomic) CGColorRef _borderColor; @property (nonatomic, retain) CALayer *wrapperLayer; @property (nonatomic, retain) CAGradientLayer *gradientLayer; - (void)setHighColor:(UIColor*)color; - (void)setLowColor:(UIColor*)color; - (void)setBorderColor:(CGColorRef)color; - (void)setCornerRadius:(float)radius; @end 

CSGradient.m(有趣的部分,无论如何)

 #import "CSGradientButton.h" @implementation CSGradientButton ... - (void)awakeFromNib { // Initialize the gradient wrapper layer wrapperLayer = [[CALayer alloc] init]; // Set its bounds to be the same of its parent [wrapperLayer setBounds:[self bounds]]; // Center the layer inside the parent layer [wrapperLayer setPosition: CGPointMake([self bounds].size.width/2, [self bounds].size.height/2)]; // Initialize the gradient layer gradientLayer = [[CAGradientLayer alloc] init]; // Set its bounds to be the same of its parent [gradientLayer setBounds:[self bounds]]; // Center the layer inside the parent layer [gradientLayer setPosition: CGPointMake([self bounds].size.width/2, [self bounds].size.height/2)]; // Insert the layer at position zero to make sure the // text of the button is not obscured [wrapperLayer insertSublayer:gradientLayer atIndex:0]; [[self layer] insertSublayer:wrapperLayer atIndex:0]; // Set the layer's corner radius [[self layer] setCornerRadius:0.0f]; [wrapperLayer setCornerRadius:0.0f]; // Turn on masking [wrapperLayer setMasksToBounds:YES]; // Display a border around the button // with a 1.0 pixel width [[self layer] setBorderWidth:1.0f]; } - (void)drawRect:(CGRect)rect { if (_highColor && _lowColor) { // Set the colors for the gradient to the // two colors specified for high and low [gradientLayer setColors: [NSArray arrayWithObjects: (id)[_highColor CGColor], (id)[_lowColor CGColor], nil]]; } [super drawRect:rect]; } - (void)setCornerRadius:(float)radius { [[self layer] setCornerRadius:radius]; // and get the wrapper for the gradient layer too [wrapperLayer setCornerRadius:radius]; } - (void)setHighColor:(UIColor*)color { // Set the high color and repaint [self set_highColor:color]; [[self layer] setNeedsDisplay]; } - (void)setLowColor:(UIColor*)color { // Set the low color and repaint [self set_lowColor:color]; [[self layer] setNeedsDisplay]; } - (void)setBorderColor:(CGColorRef)color { [[self layer] setBorderColor:color]; [[self layer] setNeedsDisplay]; } @end 

正如你所看到的,我添加了一个渐变图层可以安全遮罩的“包装”图层,而button视图的顶层CALayer可以在添加阴影时安全地设置masksToBounds = NO。 我添加一个setCornerRadius:方法来允许顶层和“包装”进行调整。

所以,而不是像[[myCustomButton layer] setCornerRadius:3.0f]; 我只是说[myCustomButton setCornerRadius:3.0f]; 正如你所看到的,它并不像我希望的那样干净。

有没有更好的办法?

这是我发现有一个圆angular,渐变和阴影的button的方式。 这个例子有一个特定的渐变,但显然可以用其他渐变代替。

 @implementation CustomButton - (id)initWithFrame:(CGRect)frame { if((self = [super initWithFrame:frame])){ [self setupView]; } return self; } - (void)awakeFromNib { [self setupView]; } # pragma mark - main - (void)setupView { self.layer.cornerRadius = 10; self.layer.borderWidth = 1.0; self.layer.borderColor = [UIColor colorWithRed:167.0/255.0 green:140.0/255.0 blue:98.0/255.0 alpha:0.25].CGColor; self.layer.shadowColor = [UIColor blackColor].CGColor; self.layer.shadowRadius = 1; [self clearHighlightView]; CAGradientLayer *gradient = [CAGradientLayer layer]; gradient.frame = self.layer.bounds; gradient.cornerRadius = 10; gradient.colors = [NSArray arrayWithObjects: (id)[UIColor colorWithWhite:1.0f alpha:1.0f].CGColor, (id)[UIColor colorWithWhite:1.0f alpha:0.0f].CGColor, (id)[UIColor colorWithWhite:0.0f alpha:0.0f].CGColor, (id)[UIColor colorWithWhite:0.0f alpha:0.4f].CGColor, nil]; float height = gradient.frame.size.height; gradient.locations = [NSArray arrayWithObjects: [NSNumber numberWithFloat:0.0f], [NSNumber numberWithFloat:0.2*30/height], [NSNumber numberWithFloat:1.0-0.1*30/height], [NSNumber numberWithFloat:1.0f], nil]; [self.layer addSublayer:gradient];} - (void)highlightView { self.layer.shadowOffset = CGSizeMake(1.0f, 1.0f); self.layer.shadowOpacity = 0.25; } - (void)clearHighlightView { self.layer.shadowOffset = CGSizeMake(2.0f, 2.0f); self.layer.shadowOpacity = 0.5; } - (void)setHighlighted:(BOOL)highlighted { if (highlighted) { [self highlightView]; } else { [self clearHighlightView]; } [super setHighlighted:highlighted]; } @end 

您也可以重写方法+layerClass来返回CAGradientLayer类,而不是插入渐变图层。 button的层次不是那个类的,你可以很容易地设置它的颜色等。

 + (Class)layerClass { return [CAGradientLayer class]; } 

我有一个类似的问题,但不是一个渐变,我有一个背景图像。 我最终解决了它使用:

 + (void) styleButton:(UIButton*)button { CALayer *shadowLayer = [CALayer new]; shadowLayer.frame = button.frame; shadowLayer.cornerRadius = 5; shadowLayer.backgroundColor = [UIColor whiteColor].CGColor; shadowLayer.opacity = 0.5; shadowLayer.shadowColor = [UIColor blackColor].CGColor; shadowLayer.shadowOpacity = 0.6; shadowLayer.shadowOffset = CGSizeMake(1,1); shadowLayer.shadowRadius = 3; button.layer.cornerRadius = 5; button.layer.masksToBounds = YES; UIView* parent = button.superview; [parent.layer insertSublayer:shadowLayer below:button.layer]; } 

真正有趣的是,如果你有一个clearColor,因为shadowLayer.backgroundColor就是没有绘制。