问题 Objective C - CAGradientLayer涵盖UILabel中的文本?


我正在尝试为我添加渐变布局 UILabel 由于某些原因 CAGradientLayer 涵盖我的文字。 我做错了什么

- (void)viewDidLoad {
   [super viewDidLoad];

   CAGradientLayer *gradient = [CAGradientLayer layer];
   gradient.frame = CGRectMake(0, 0, myLabel.frame.size.width, myLabel.frame.size.height);
   gradient.colors = myColors;
   [myLabel.layer insertSublayer:gradient atIndex:0];
}

6279
2017-08-26 19:05


起源



答案:


CAGradientLayer 覆盖标签的文本,因为文本是通过添加子图层明确涵盖的超级图层的内容绘制的。

最简单的解决方案是使用两个视图。一个 UIView 您重写的子类 +[UIView layerClass] 并返回一个 [CAGradientLayer]。添加一个好的init方法来设置渐变。

下一个小狗加了 UILabel 作为自定义渐变视图的子视图。


12
2017-08-26 19:18



另外,出于对我所接受的特定实现的好奇心,即使已知,依赖它也是一个非常糟糕的想法;我没有检查过,但据推测,UILabel在iOS 3.2中使用了CATextLayer? - Tommy
@Tommy - UILabel 没有支持 CATextLayer 3.2之前或之后。您可以通过“”轻松检查po [[someLabel layer] class]“这将产生一个基本的 CALayer。从那以后,它在视觉上也很明显 CATextLayer 没有子像素抗锯齿但是 UILabel 做。 - PeyloW
类型并不总是有用的,因为任何曾经尝试过的人[str isKindOfClass:[NSMutableString class]]都可以证明。这是一个桥接问题,显然CALayer没有与任何东西正式免费接合,但假设在CALayer中没有类似的类聚类或别名就是:一个假设。我认为亚像素抗锯齿线索是相当明确的。 - Tommy
谢谢,奇怪,因为这在UIButton上工作正常,但在UILabel上没有。我认为他们都用同样的方式来绘制文字。 - aryaxt
@aryaxt - 如果你看一下 UIButton.h 头文件你会看到的 UIButton 实际上有一个名为的实例变量 _titleView。因此,对于按钮视图,这很简单,因为按钮不会绘制自己的文本,这是由子标签子视图完成的。 - PeyloW


答案:


CAGradientLayer 覆盖标签的文本,因为文本是通过添加子图层明确涵盖的超级图层的内容绘制的。

最简单的解决方案是使用两个视图。一个 UIView 您重写的子类 +[UIView layerClass] 并返回一个 [CAGradientLayer]。添加一个好的init方法来设置渐变。

下一个小狗加了 UILabel 作为自定义渐变视图的子视图。


12
2017-08-26 19:18



另外,出于对我所接受的特定实现的好奇心,即使已知,依赖它也是一个非常糟糕的想法;我没有检查过,但据推测,UILabel在iOS 3.2中使用了CATextLayer? - Tommy
@Tommy - UILabel 没有支持 CATextLayer 3.2之前或之后。您可以通过“”轻松检查po [[someLabel layer] class]“这将产生一个基本的 CALayer。从那以后,它在视觉上也很明显 CATextLayer 没有子像素抗锯齿但是 UILabel 做。 - PeyloW
类型并不总是有用的,因为任何曾经尝试过的人[str isKindOfClass:[NSMutableString class]]都可以证明。这是一个桥接问题,显然CALayer没有与任何东西正式免费接合,但假设在CALayer中没有类似的类聚类或别名就是:一个假设。我认为亚像素抗锯齿线索是相当明确的。 - Tommy
谢谢,奇怪,因为这在UIButton上工作正常,但在UILabel上没有。我认为他们都用同样的方式来绘制文字。 - aryaxt
@aryaxt - 如果你看一下 UIButton.h 头文件你会看到的 UIButton 实际上有一个名为的实例变量 _titleView。因此,对于按钮视图,这很简单,因为按钮不会绘制自己的文本,这是由子标签子视图完成的。 - PeyloW


我有同样的问题。我制作了这个方法来获取形状图层的参考,或者如果它不存在则生成它。此方法确保将该图层放在后面,以便它不会覆盖标签文本图层。只需使用它,你应该都很好,不需要额外的子类。

- (CAShapeLayer*) getShapeLayerForObject: (UIView*) object{
    CAShapeLayer *maskLayer;
    int loc = -1;
    for(int x = 0; x < object.layer.sublayers.count; x++){
        if([[object.layer.sublayers objectAtIndex:x] isKindOfClass:[CAShapeLayer class]]){
            loc = x;
            break;
        }
    }
    if(loc > -1){
        maskLayer = (CAShapeLayer*) [object.layer.sublayers objectAtIndex:loc];
    }else{
        maskLayer = [[CAShapeLayer alloc] init];
        [object.layer insertSublayer:maskLayer atIndex:0];

    }
    return maskLayer;
}

0
2018-04-04 18:30





例如,如果您需要子类化您的 UILabel,然后添加一些 CALayer 其中涵盖了文字,建议添加 CATextLayer 到你的 CALayer,这是一个很快的例子:

@IBDesignable class BWRoundedLabel: UILabel {

    override var text: String? {
        didSet {
            updateView()
        }
    }

    @IBInspectable override var shadowColor: UIColor? {

        didSet {
            updateView()
        }
    }

    private func updateView() {

        let width = bounds.size.width - 1
        let height = bounds.size.height - 1

        let shadowLayer = CAShapeLayer()
        shadowLayer.path = UIBezierPath(roundedRect: CGRectMake(0, 0, width, height), cornerRadius: width/2).CGPath
        shadowLayer.fillColor = UIColor.yellowOrange().CGColor
        shadowLayer.shadowColor = shadowColor?.CGColor
        shadowLayer.shadowPath = shadowLayer.path
        shadowLayer.shadowOffset = CGSize(width: 0, height: 1.0)
        shadowLayer.shadowOpacity = 1
        shadowLayer.shadowRadius = 0

        let textLayer = CATextLayer()
        textLayer.foregroundColor = UIColor.whiteColor().CGColor
        textLayer.string = text
        textLayer.fontSize = font.pointSize
        textLayer.font = "Calibri-Bold"
        textLayer.alignmentMode = kCAAlignmentCenter
        textLayer.frame = CGRectMake(0, (height - 16)/2, width, 16)

        if let sublayers = layer.sublayers {
            for sublayer in sublayers {
                sublayer.removeFromSuperlayer()
            }
        }

        layer.insertSublayer(shadowLayer, atIndex: 0)
        layer.insertSublayer(textLayer, atIndex: 1)
    }
}

0
2018-05-02 10:27