Swift 中的自定义 UI 元素:子类化 CALayer 并覆盖 drawInContext 导致像素化绘图

Posted

技术标签:

【中文标题】Swift 中的自定义 UI 元素:子类化 CALayer 并覆盖 drawInContext 导致像素化绘图【英文标题】:Custom UI element in Swift: Subclassing CALayer and overriding drawInContext results in pixelated drawing 【发布时间】:2014-11-15 12:07:48 【问题描述】:

我目前正在学习如何实现自定义控件。我不可避免地偶然发现了 CALayer 的可能性,因为当需要执行复杂的动画时,使用 UIImage 不够灵活。

我想将 UIView 用作 CALayer 的“容器”,以便它的宽度和高度始终与 UIView 相同(出于灵活性目的)。

我继承了 CALayer 并覆盖了 drawInContext() 方法。

这是我在屏幕上看到的结果:

绘图看起来像素化和模糊。我正在使用 PaintCode 为我生成绘图代码。

这是自定义的 CALayer:

class SegmentActive: CALayer 

func frameSetup() -> CGRect 

    let frameWidth:CGFloat = superlayer.frame.width
    let frameHeight:CGFloat = superlayer.frame.height

    let frame = CGRectMake(0, 0, frameWidth, frameHeight)

    println("\(superlayer.frame.width) // \(superlayer.frame.height)")

    return frame



override func drawInContext(ctx: CGContext!) 

    UIGraphicsPushContext(ctx)

    CalorieCalculatorUI.drawSegControlActiveBase(frameSetup())

    UIGraphicsPopContext()


我是这样使用它的:

class ViewController: UIViewController 

@IBOutlet weak var leftSegmentUIView: UIView!

override func viewDidLoad() 

    let activeSegment:SegmentActive = SegmentActive()

    leftSegmentUIView.layer.addSublayer(activeSegment)

    activeSegment.frame = activeSegment.frameSetup()

    activeSegment.setNeedsDisplay()

    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.




override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.

我在这里做错了什么? :(

【问题讨论】:

【参考方案1】:

tl;dr:您必须将图层的contentsScale 设置为大于默认值 1.0 的值。


图层的比例因子默认为 1。这会更改该图层的内容缓冲区的大小:

适用于 [...] 和通过 -drawInContext: 提供的内容(即,如果 contentsScale 是两个 -drawInContext: 将绘制到两倍于层边界的缓冲区中)

由于您在像素比设备屏幕少的上下文中进行自定义绘图,因此绘图看起来像素化。对于传统的“视网膜”屏幕,您所期望的比例因子是2.0,但随着最近推出的 iPhone 6+ 的推出,还有 3.0 的比例因子。好消息是您可以从UIScreen 获取设备规模。

【讨论】:

非常感谢大卫!你是绝对的传奇!你的答案和博客总是充满了知识和智慧。再次感谢您好心的先生! 确实如此。只是 FTR 一个常见的、类似的、相关的问题是,当您(比如说)为类似的大小设置动画时,您需要 self.layer.shouldRasterize = YES; 嘿@JoeBlow,谢谢!我确实计划为很多东西制作动画,所以我相信它会派上用场。 我真的希望它有所帮助。我有时会因为忘记这一点而浪费时间!!

以上是关于Swift 中的自定义 UI 元素:子类化 CALayer 并覆盖 drawInContext 导致像素化绘图的主要内容,如果未能解决你的问题,请参考以下文章

子类化从 xib 创建的自定义视图

想知道如何以编程方式在 swift 3.0 中对 UITableViewCell 进行子类化?

如何为 UIView 的自定义子类设置约束?

如何使子类化的自定义 Django 表单字段不再是必需的?

框架中的自定义 ui 组件未呈现到故事板

Appium 自动化测试:如何从 android [android.view.View] 中的自定义 UI 中获取元素或文本