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. 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.
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. One might create a bitmap graphics context to create a CGLaye开发者_运维知识库r, 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.
So my question is, is it really impossible to create a window graphics context outside drawRect:
to make a CGLayer object based on it. Or, is there a better way to create and store a CGLayer object for on-screen drawing that may be shared by multiple views? 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?
Yes, you can create a drawing context for a CALayer from a bitmap.
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. 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.
The following examples in Swift show how I have done what the original question asks, in both iOS and OSX.
Note: when you create a CGLayer, the graphics context that you provide is used solely as a reference to initialise the layer. 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.
In this example I create a CGLayer in the view controller and do some drawing on it. Then I render it onto the screen in the drawRect() method of a view.
iOS example
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
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
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
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)
}
}
精彩评论