2014-12-13 90 views
1

如何从按钮背景中减去标题文字的形状?透明UIButton标题

enter image description here

我创建一个自定义的UIButton类。目前添加边框和文字颜色的代码看起来就像这样

layer.borderWidth = 2.0 
layer.borderColor = buttonColor.CGColor 
layer.cornerRadius = (CGFloat(bounds.height) + paddingVertical * 2.0)/2.0 
setTitleColor(buttonColor, forState: UIControlState.Normal) 

任何关于如何从背景减去按钮标题形状的建议。我是否需要将所有这些渲染为图像,还是有更好的选择?

+0

如果你有这样的图像,这可以很容易地实现。 – Mrunal 2014-12-13 11:05:24

+0

我正在寻找一个编程解决方案 – Bernd 2014-12-13 11:15:43

+1

这里的一点点改变可能会帮助你:http://stackoverflow.com/questions/23515100/ios-uibutton-with-transparent-title-on-white-background – Mrunal 2014-12-13 11:18:50

回答

4

我已经写了一些代码对你来说,(可在GitHub上https://github.com/purrrminator/AKStencilButton)我叫AKStencilButton的UIButton子类:

#import "AKStencilButton.h" 
#import <QuartzCore/QuartzCore.h> 

@interface AKStencilButton() 
{ 
    UIColor * _buttonColor; 
} 
@end 

@implementation AKStencilButton 

-(id)initWithCoder:(NSCoder *)aDecoder 
{ 
    if (self = [super initWithCoder:aDecoder]){ 
     [self setupDefaults]; 
    } 
    return self; 
} 
-(instancetype)initWithFrame:(CGRect)frame 
{ 
    if (self = [super initWithFrame:frame]){ 
     [self setupDefaults]; 
    } 
    return self; 
} 
-(void)setupDefaults 
{ 
    self.backgroundColor = [UIColor redColor]; 
    self.layer.cornerRadius = 4; 
    self.clipsToBounds = YES; 
} 
-(void)layoutSubviews 
{ 
    [super layoutSubviews]; 
    [self refreshMask]; 
} 
-(void)setTitleColor:(UIColor *)color forState:(UIControlState)state 
{ 
    [super setTitleColor:[UIColor clearColor] forState:state]; 
} 
-(void)refreshMask 
{ 
    self.titleLabel.backgroundColor = [UIColor clearColor]; 
    [self setTitleColor:[UIColor clearColor] forState:UIControlStateNormal]; 

    NSString * text = self.titleLabel.text; 
    CGSize buttonSize = self.bounds.size; 
    UIFont * font = self.titleLabel.font; 

    NSDictionary* attribs = @{NSFontAttributeName: self.titleLabel.font}; 
    CGSize textSize = [text sizeWithAttributes:attribs]; 


    UIGraphicsBeginImageContextWithOptions(buttonSize, NO, [[UIScreen mainScreen] scale]); 
    CGContextRef ctx = UIGraphicsGetCurrentContext(); 
    CGContextSetFillColorWithColor(ctx, [UIColor whiteColor].CGColor); 
    CGPoint center = CGPointMake(buttonSize.width/2-textSize.width/2, buttonSize.height/2-textSize.height/2); 

    UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, buttonSize.width, buttonSize.height)]; 
    CGContextAddPath(ctx, path.CGPath); 
    CGContextFillPath(ctx); 
    CGContextSetBlendMode(ctx, kCGBlendModeDestinationOut); 

    [text drawAtPoint:center withAttributes:@{NSFontAttributeName:font}]; 
    UIImage* viewImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    CALayer *maskLayer = [CALayer layer]; 
    maskLayer.contents = (__bridge id)(viewImage.CGImage); 
    maskLayer.frame = self.bounds; 
    self.layer.mask = maskLayer; 
} 
@end 

它看起来像这样(对不起,彩虹):

enter image description here

+1

也许回答这个问题,但答案应该在[so]上发布,而不仅仅在github上。 – 2014-12-13 17:32:27

+0

好的。现在看起来好吗? – 2014-12-13 17:39:03

+0

谢谢。看看现在在Swift中重写这个... – Bernd 2014-12-13 21:57:39

4

我向UIView添加了以下方法来解决这个问题:

-(void)maskSubviews:(NSArray*)subviews { 
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0); 
    CGContextRef context = UIGraphicsGetCurrentContext(); 

    CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor); 
    CGContextFillRect(context, self.bounds); 

    CGContextSetBlendMode(context, kCGBlendModeDestinationOut); 
    for (UIView *view in subviews) { 
     CGPoint origin = [view convertPoint:CGPointZero toView:self]; 
     CGContextTranslateCTM(context, origin.x, origin.y); 
     [view.layer renderInContext:context]; 
     CGContextTranslateCTM(context, -origin.x, -origin.y); 
    } 
    UIImage* mask = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    self.maskView = [[UIImageView alloc] initWithImage:mask]; 
} 

只需用你想遮盖的视图来调用它。例如:

[button maskSubviews: @[button.titleLabel, button.imageView]] 
1

我将@ purrrminator的解决方案转换为Swift 3,只是主要的方法。

func clearTextButton(button: UIButton, title: NSString, color: UIColor) { 
    button.backgroundColor = color 
    button.titleLabel?.backgroundColor = UIColor.clear() 
    button.setTitleColor(UIColor.clear(), for: .normal) 
    button.setTitle(title as String, for: []) 
    let buttonSize: CGSize = button.bounds.size 
    let font: UIFont = button.titleLabel!.font 
    let attribs: [String : AnyObject] = [NSFontAttributeName: button.titleLabel!.font] 
    let textSize: CGSize = title.size(attributes: attribs) 
    UIGraphicsBeginImageContextWithOptions(buttonSize, false, UIScreen.main().scale) 
    let ctx: CGContext = UIGraphicsGetCurrentContext()! 
    ctx.setFillColor(UIColor.white().cgColor) 
    let center: CGPoint = CGPoint(x: buttonSize.width/2 - textSize.width/2, y: buttonSize.height/2 - textSize.height/2) 
    let path: UIBezierPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: buttonSize.width, height: buttonSize.height)) 
    ctx.addPath(path.cgPath) 
    ctx.fillPath() 
    ctx.setBlendMode(.destinationOut) 
    title.draw(at: center, withAttributes: [NSFontAttributeName: font]) 
    let viewImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()! 
    UIGraphicsEndImageContext() 
    let maskLayer: CALayer = CALayer() 
    maskLayer.contents = ((viewImage.cgImage) as! AnyObject) 
    maskLayer.frame = button.bounds 
    button.layer.mask = maskLayer 
} 
+2

太多的强制解包选项。在所有这些情况下,条件解包将会更好:如果让font = button.titleLabel?.font,{...},如果让ctx = UIGraphicsGetCurrentContext(){...}等等。 – GK100 2016-08-09 17:15:36

+0

@ GK100确实,只是一个快速和肮脏的变化。一些变量是有保证的,比如titleLabel,因为我之前设置了标题。 – 2016-08-11 00:17:42