首页 文章

UIButton带渐变,圆角,边框和阴影

提问于
浏览
16

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

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

我遇到了一个问题,其中按钮层上的setMasksToBounds将允许A)显示阴影,但也允许渐变层显示超出圆角或B)渐变层剪切到圆角,但不是允许投影显示

我对这个问题的解决方案似乎很笨拙(尽管它有效)我想知道是否有人知道更好和/或更清洁的方法来完成同样的事情 . 这是我的代码:

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

如您所见,我添加了一个渐变图层可以安全遮盖的“包装”图层,而按钮视图的顶级CALayer可以在添加投影图时安全地设置masksToBounds = NO . 我添加了一个setCornerRadius:方法来允许顶层和'包装器'进行调整 .

所以,而不是做 [[myCustomButton layer] setCornerRadius:3.0f]; 之类的事情,我只是说 [myCustomButton setCornerRadius:3.0f]; 正如你所看到的那样,它希望 .

有没有更好的办法?

3 回答

  • 4

    这是我发现有一个圆角,渐变和阴影按钮的方式 . 此示例具有一个特定渐变,但显然可以用其他渐变替换 .

    @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
    
  • 22

    您也可以覆盖方法 +layerClass 以返回 CAGradientLayer 类,而不是插入渐变图层 . 按钮的图层比该图层的图层要多,您可以轻松设置其颜色等 .

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

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

    + (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只是没有绘制 .

相关问题