[ios] UIButton w / gradient, esquinas redondeadas, borde y sombra paralela


Answers

En lugar de insertar una capa de degradado, también puede anular el método +layerClass para devolver la clase CAGradientLayer . La capa del botón es diferente de esa clase, y puede establecer fácilmente sus colores, etc.

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

Hay algunas preguntas similares en el sitio, pero estoy buscando algo específico y ligeramente diferente.

Seguí la dirección dada aquí: http://www.cimgf.com/2010/01/28/fun-with-uibuttons-and-core-animation-layers/ subclase UIButton para crear una clase genérica que pueda especifique los colores degradados, en lugar de tratar de usar una imagen estática.

Me encontré con un problema donde setMasksToBounds en la capa del botón permitiría A) mostrar la sombra paralela, pero también permitir que la capa de degradado se muestre más allá de las esquinas redondeadas O B) la capa de degradado para recortar en las esquinas redondeadas, pero no permitir que la sombra paralela muestre

Mi solución al problema parecía torpe y (aunque funciona) quería ver si alguien sabía de una manera mejor y / o más limpia de lograr lo mismo. Aquí está mi código:

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 (las partes interesantes, de todos modos)

#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

Como puede ver, agrego una capa 'envoltura' a la que la capa de degradado puede enmascarar de forma segura, mientras que el nivel superior CALayer de la vista de botón puede establecer con seguridad masksToBounds = NO cuando se agrega la sombra de gotas. Agrego un método setCornerRadius: para permitir que tanto la capa superior como la 'envoltura' se ajusten.

Entonces, en lugar de hacer algo como [[myCustomButton layer] setCornerRadius:3.0f]; Solo digo [myCustomButton setCornerRadius:3.0f]; Como puede ver, no es tan limpio como esperaba.

¿Hay una mejor manera?




Links