【问题标题】:Transparent UIButton title透明的 UIButton 标题
【发布时间】:2014-12-13 11:04:32
【问题描述】:

如何从按钮背景中减去标题文本的形状?

我创建了一个自定义 UIButton 类。目前添加边框和文本颜色的代码看起来很简单

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

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

【问题讨论】:

  • 如果你有这样的图像,这很容易实现。
  • 我正在寻找程序化解决方案
  • 这里的小改动可能会对您有所帮助:stackoverflow.com/questions/23515100/…
  • 用你想要的任何颜色创建一个渐变层,然后将其设置为你的文本标签,这样就可以了。
  • 谢谢,但是模糊的背景内容不断变化。不幸的是,静态、不透明的标题(有或没有渐变)并不能解决问题。

标签: ios swift uibutton calayer


【解决方案1】:

swift 4 的扩展

extension UIButton{
func clearColorForTitle() {

    let buttonSize = bounds.size

    if let font = titleLabel?.font{
        let attribs = [NSAttributedStringKey.font: font]

        if let textSize = titleLabel?.text?.size(withAttributes: attribs){
            UIGraphicsBeginImageContextWithOptions(buttonSize, false, UIScreen.main.scale)

            if let ctx = UIGraphicsGetCurrentContext(){
                ctx.setFillColor(UIColor.white.cgColor)

                let center = CGPoint(x: buttonSize.width / 2 - textSize.width / 2, y: buttonSize.height / 2 - textSize.height / 2)
                let path = UIBezierPath(rect: CGRect(x: 0, y: 0, width: buttonSize.width, height: buttonSize.height))
                ctx.addPath(path.cgPath)
                ctx.fillPath()
                ctx.setBlendMode(.destinationOut)

                titleLabel?.text?.draw(at: center, withAttributes: [NSAttributedStringKey.font: font])

                if let viewImage = UIGraphicsGetImageFromCurrentImageContext(){
                    UIGraphicsEndImageContext()

                    let maskLayer = CALayer()
                    maskLayer.contents = ((viewImage.cgImage) as AnyObject)
                    maskLayer.frame = bounds

                    layer.mask = maskLayer
                }
            }
        }
    }
}

用法:

button.clearColorForTitle()

【讨论】:

  • 一个小提示:你需要在layoutSubviews() 中也调用clearColorForTitle(),因为当按钮边界在创建过程中更改为其他内容时(例如以编程方式设置内容插入),那么一切都会是弄乱。清除标题颜色也是有意义的,以防万一,这样它在“孔”下方不可见。
【解决方案2】:

我已经为您编写了一些代码,我的 UIButton 子类称为 AKStencilButton(可在 github https://github.com/purrrminator/AKStencilButton 上获得):

#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

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

【讨论】:

  • 也许这可以回答问题,但答案应该发布在 hereStack Overflow,而不仅仅是在 github 上。
  • 好的。现在好看了吗?
  • 谢谢。现在正在考虑用 Swift 重写它……
【解决方案3】:

我在 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]]

【讨论】:

    【解决方案4】:

    我将 @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
    }
    

    【讨论】:

    • 强制展开的选项太多。在所有这些情况下,条件展开会更好:if let font = button.titleLabel?.font, { ... }, if let ctx = UIGraphicsGetCurrentContext() { ... } 等等。
    • @GK100 没错,这只是一个快速而肮脏的改变。一些变量是有保证的,比如titleLabel,就像我之前设置的标题一样。
    猜你喜欢
    • 2014-06-24
    • 1970-01-01
    • 2016-05-06
    • 2016-11-04
    • 1970-01-01
    • 1970-01-01
    • 2012-05-26
    • 1970-01-01
    • 2019-01-25
    相关资源
    最近更新 更多