На сайте есть несколько похожих вопросов, но я ищу что-то конкретное и немного другое.
Я следовал приведенному здесь направлению: 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];
Как вы можете видеть, это не так чисто, как я надеюсь.
Есть ли лучший способ?