【问题标题】:Is it safe to add a "stolen" UILabel's layer to some other CALayer's sublayer?将“被盗”的 UILabel 图层添加到其他 CALayer 的子图层是否安全?
【发布时间】:2017-01-10 16:18:23
【问题描述】:

我阅读了thisthis,但它们似乎没有解决这个问题。而this 的答案似乎与NSCoding 和朋友们相去甚远,所以...

考虑:

- (NSAttributedString *) attributedStringForText: (NSString *) text {
    NSMutableAttributedString* attrStr = [[NSMutableAttributedString alloc] initWithString:text];
    UIFont * bigF = [UIFont fontWithName:@"OpenSans-Extrabold" size:20.0f] ;
    UIFont * smaF = [UIFont fontWithName:@"OpenSans-Extrabold" size:12.0f] ;

    [attrStr addAttribute:NSFontAttributeName value:bigF range:(NSRange){0, 3}] ;
    [attrStr addAttribute:NSFontAttributeName value:smaF range:(NSRange){3, 6}] ;
    [attrStr addAttribute:NSFontAttributeName value:bigF range:(NSRange){6, [text length]-6}] ;

    [attrStr addAttribute:NSBackgroundColorAttributeName value:[UIColor brownColor] range:(NSRange){3, 6}] ;
    return attrStr ;
}

- (CALayer *) stealLayerFromUILabelForText: (NSString *) text inRect: (CGRect) bounds {
    UILabel * label = [[UILabel alloc] initWithFrame:bounds] ;
    label.textColor = [UIColor whiteColor] ;
    label.font = [UIFont fontWithName:@"OpenSans-Extrabold" size:20.0f] ;
    label.attributedText = [self attributedStringForText:text] ;
    [label sizeToFit] ;
    [label.layer display] ; // Yup!
    return label.layer ;
}

- (void) setupLayer: (CALayer *) tileLayer
               text: (NSString *) text
              index: (NSUInteger) index {

    CGRect (^center_rect)(CGRect, CGRect) = ^CGRect (CGRect r, CGRect into) {
        CGRect centered = into ;
        centered.origin.x += (into.size.width - r.size.width) / 2.0f ;
        centered.origin.y += (into.size.height - r.size.height) / 2.0f ;
        centered.size = r.size ;
        return centered ;
    } ;

    CALayer * layer = [self stealLayerFromUILabelForText:text inRect:tileLayer.bounds] ;
    CGRect frame = center_rect(layer.bounds, tileLayer.bounds) ;

    [tileLayer addSublayer:layer] ;

    layer.frame = frame ;
}

这行得通:

但我担心我会以某种方式滥用 UILabel 和 CALayer。一方面,UIViewUILabel 和所有这些都只是 真正的 CALayer 层次结构之上的薄触摸感知单板。 OTOH,我不知何故依赖这里可能有许多甚至没有陈述的假设。

任何人都知道为什么这会在未来进一步崩溃,或者更好的是,可以证明它不会?

【问题讨论】:

  • 需要考虑的事项 - [CALayer display] 文档的第一行声明“不要直接调用此方法”。这意味着,如果您这样做,Apple 将来会更改某些内容,它可能会崩溃。也许不太可能,但绝对有可能。
  • 《iOS 核心动画:Nick Lockwood 的高级技术》中有一个先例:books.google.co.uk/… ...
  • 你可以在 iOS 7 中使用快照 API
  • 您能详细说明一下吗?快照 API 会给我一个光栅化的位图,我需要一个屏幕外视图来进行快照。这些对我来说似乎都不是很可口。探索其他方法来做同样的事情当然很有趣,但我更倾向于使层窃取方法无效(或者验证是否我真的很幸运:-))的原因。

标签: ios objective-c uilabel calayer


【解决方案1】:

我从 2013 年开始使用这种技术,现在它仍然很稳定。所以是的,我认为现在这是安全的。以前我在 iOS 4 或 5 上没有调用 -display 就这样做了,当针对较新的 SDK 编译时,它不再工作,所以感谢这个花絮。

如果您正在寻找其他选项,这里有更多信息:Add text to CALayer

【讨论】:

    【解决方案2】:

    这种技术在 iOS 10 中仍然有效。IMO 一个 UIView(在本例中为 UILabel)只是其支持 CALayer 的委托,因此直接操作底层 CALayer 应该是安全的。唯一的问题是,如果您不将标签添加为子视图,则标签将被释放,并且底层 layer.delegate 将变为 nil,并且文本永远不会有机会呈现。

    所以我们需要一种在标签释放之前强制渲染的方法。但是值得一提的是,不应根据 Apple 的文档直接调用 [CALayer display]。所以基于同样的想法,考虑一个安全的替代方案[CALayer displayIfNeeded]

    - (CALayer *) stealLayerFromUILabelForText: (NSString *) text inRect: (CGRect) bounds {
        UILabel * label = [[UILabel alloc] initWithFrame:bounds] ;
        label.textColor = [UIColor whiteColor] ;
        label.font = [UIFont fontWithName:@"OpenSans-Extrabold" size:20.0f] ;
        label.attributedText = [self attributedStringForText:text] ;
        [label sizeToFit] ;
        [label.layer displayIfNeeded] ;
        return label.layer ;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多