简体   繁体   English

在UIView的drawRect外部为iOS中的CGLayer创建窗口图形上下文

[英]Creating a window graphics context for a CGLayer in iOS outside drawRect: of UIView

UIView creates a window graphics context before a custom drawRect: method is invoked, so inside the method I can get the graphics context. UIView在调用自定义drawRect:方法之前创建窗口图形上下文,因此在该方法内部,我可以获取图形上下文。 However, it seems that the only way to get a window graphics context in iOS, so I can make a CGLayer object based on a window graphics context only in a custom drawRect: method of a UIView object. 但是,似乎这在iOS中获取窗口图形上下文的唯一方法 ,因此我只能在UIView对象的自定义drawRect:方法中基于窗口图形上下文创建CGLayer对象。

However, I might want a model object to contain a CGLayer object, which is created with the model object itself, and later a lot of views use the layer to draw its content on their own views. 但是,我可能希望模型对象包含一个CGLayer对象,该对象是由模型对象本身创建的,后来许多视图使用该图层在自己的视图上绘制其内容。 One might create a bitmap graphics context to create a CGLayer, but then everything drawn on the screen using the CGLayer object will have characteristics of a bitmap context, as Apple's documents say that drawing with a CGLayer object is restricted to the type of the graphics context used to create the layer. 人们可能会创建一个位图图形上下文来创建一个CGLayer,但是使用CGLayer对象在屏幕上绘制的所有内容都会具有位图上下文的特征,因为Apple的文档说,使用CGLayer对象进行的绘制仅限于图形上下文的类型。用于创建图层。

So my question is, is it really impossible to create a window graphics context outside drawRect: to make a CGLayer object based on it. 所以我的问题是,是否真的不可能在drawRect:之外创建窗口图形上下文drawRect:基于它创建CGLayer对象。 Or, is there a better way to create and store a CGLayer object for on-screen drawing that may be shared by multiple views? 或者,是否有更好的方法为屏幕上的绘图创建和存储CGLayer对象,该对象可能由多个视图共享? Or is it a completely bogus idea to have such a shared CGLayer object outside a UIView object for a reason I don't realize? 还是出于我不知道的原因而在UIView对象之外拥有这样一个共享的CGLayer对象是完全假的想法吗?

The following examples in Swift show how I have done what the original question asks, in both iOS and OSX. Swift中的以下示例说明了如何在iOS和OSX中完成原始问题的要求。

Note: when you create a CGLayer, the graphics context that you provide is used solely as a reference to initialise the layer. 注意:创建CGLayer时,您提供的图形上下文仅用作初始化图层的参考。 No content or anything are sent to it - it just has to be the right TYPE of context so that the API knows what sort of layer to create. 没有内容或任何内容发送给它-它只必须是正确的上下文类型,以便API知道要创建哪种层。

In this example I create a CGLayer in the view controller and do some drawing on it. 在此示例中,我在视图控制器中创建一个CGLayer并在其上进行一些绘制。 Then I render it onto the screen in the drawRect() method of a view. 然后,使用视图的drawRect()方法将其渲染到屏幕上。


iOS example iOS示例

The view controller 视图控制器

import UIKit

class ViewController: UIViewController {
    @IBOutlet var myView: MyView!

    override func viewWillAppear(animated: Bool) {
        // get the current graphics context - any context relevant to the screen 
        // will do for this purpose
        let currentGraphicsContext = UIGraphicsGetCurrentContext()

        // create a GCLayer with low level properties appropriate to the device 
        // screen and a size of 100 x 100
        // this process doesn't send any content to windowGraphicsContext, it just 
        // copies some of the low level fields about the screen
        let newLayer = CGLayerCreateWithContext(currentGraphicsContext, 
                                                CGSize(width: 100, height: 100), 
                                                nil)

        // store a reference to the layer in a property of the view so that the 
        // view can display it
        myView.layerRef = newLayer

        // create a new graphics context for the layer so that we can draw on it
        let myLayerContext = CGLayerGetContext(newLayer)

        // draw some content on the layer
        CGContextSetFillColorWithColor(myLayerContext, UIColor.redColor().CGColor)
        CGContextFillRect(myLayerContext, 
                          CGRect(x: 0, y: 0, width: 100, height: 50))
        CGContextSetFillColorWithColor(myLayerContext, UIColor.blueColor().CGColor)
        CGContextFillRect(myLayerContext, 
                          CGRect(x: 0, y: 50, width: 50, height: 50))
    }
}

The UIView subclass UIView子类

import UIKit

class MyView: UIView {

    // a reference to the layer created by the view controller
    var layerRef: CGLayer?

    override func drawRect(rect: CGRect) {
        // get a graphics context for the view
        let myViewGraphicsContext = UIGraphicsGetCurrentContext()

        // draw the layer into the view
        CGContextDrawLayerAtPoint(myViewGraphicsContext, 
                                  CGPoint(x: 20 , y: 20), 
                                  self.layerRef)
    }
}

OSX example OSX范例

The view controller 视图控制器

import Cocoa

class ViewController: NSViewController {
    @IBOutlet var myView: MyView!

    override func viewWillAppear() {
        // get a graphics context for the window that contains the view - any 
        // context relevant to the screen will do
        let windowGraphicsContext = NSGraphicsContext(window: myView.window!)

        // create a GCLayer with low level properties appropriate to the device 
        // screen and a size of 100 x 100
        // this process doesn't send any content to windowGraphicsContext, it just 
        // copies some of the low level fields about the screen
        let newLayer = CGLayerCreateWithContext(windowGraphicsContext.CGContext, 
                     CGSize(width: 100, height: 100), nil)

        // store a reference to the layer in a property of the view, so that the 
        // view can display it
        myView.layerRef = newLayer

        // create a new graphics context for the layer so that we can draw on it
        let myLayerContext = CGLayerGetContext(newLayer)

        // do some drawing on the layer
        CGContextSetFillColorWithColor(myLayerContext, NSColor.redColor().CGColor)
        CGContextFillRect(myLayerContext, 
                          CGRect(x: 0, y: 0, width: 100, height: 50))
        CGContextSetFillColorWithColor(myLayerContext, NSColor.blueColor().CGColor)
        CGContextFillRect(myLayerContext, 
                          CGRect(x: 0, y: 50, width: 50, height: 50))
    }
}

The NSView subclass NSView子类

import Cocoa

class MyView: NSView {

    // a reference to the layer created by the view controller
    var layerRef: CGLayer?

    override func drawRect(dirtyRect: NSRect) {    
        super.drawRect(dirtyRect)

        // get a graphics context for the view
        let graphicsContext = NSGraphicsContext.currentContext()?.CGContext

        // draw the layer into the view
        CGContextDrawLayerAtPoint(graphicsContext, 
                                  CGPoint(x: 20 , y: 20), 
                                  self.layerRef)
    }
}

Yes, you can create a drawing context for a CALayer from a bitmap. 是的,您可以从位图为CALayer创建图形上下文。

But the contents of a CGLayer needs a backing bitmap, since it does not save the symbolic (resolution independent) drawing vectors when drawn into, only the resulting pixels. 但是CGLayer的内容需要一个后备位图,因为在绘制时,它不保存符号(与分辨率无关)的绘制矢量,而仅保存生成的像素。 So either you create the backing bitmap, or you use the one handed you by a UIView, or you recreate/redraw the bits from your own command list when required. 因此,您可以创建支持位图,也可以使用UIView所提供的一位,也可以在需要时从自己的命令列表中重新创建/重画这些位。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM