Die Geld-zurück-garantierte, Stahlbeton-solide Methode, um eine Ansicht zum synchronen Zeichnen zu zwingen (bevor Sie zum aufrufenden Code zurückkehren), besteht darin, die CALayer
Interaktionen des UIView
Benutzers mit Ihrer Unterklasse zu konfigurieren .
Erstellen Sie in Ihrer UIView-Unterklasse eine displayNow()
Methode, die der Ebene sagt, dass sie " Kurs für die Anzeige festlegen " und dann "so machen " soll:
Schnell
/// Redraws the view's contents immediately.
/// Serves the same purpose as the display method in GLKView.
public func displayNow()
{
let layer = self.layer
layer.setNeedsDisplay()
layer.displayIfNeeded()
}
Ziel c
/// Redraws the view's contents immediately.
/// Serves the same purpose as the display method in GLKView.
- (void)displayNow
{
CALayer *layer = self.layer;
[layer setNeedsDisplay];
[layer displayIfNeeded];
}
Implementieren Sie auch eine draw(_: CALayer, in: CGContext)
Methode, die Ihre private / interne Zeichenmethode aufruft (was funktioniert, da jede a UIView
ist CALayerDelegate
) :
Schnell
/// Called by our CALayer when it wants us to draw
/// (in compliance with the CALayerDelegate protocol).
override func draw(_ layer: CALayer, in context: CGContext)
{
UIGraphicsPushContext(context)
internalDraw(self.bounds)
UIGraphicsPopContext()
}
Ziel c
/// Called by our CALayer when it wants us to draw
/// (in compliance with the CALayerDelegate protocol).
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context
{
UIGraphicsPushContext(context);
[self internalDrawWithRect:self.bounds];
UIGraphicsPopContext();
}
Und erstellen Sie Ihre benutzerdefinierte internalDraw(_: CGRect)
Methode zusammen mit ausfallsicher draw(_: CGRect)
:
Schnell
/// Internal drawing method; naming's up to you.
func internalDraw(_ rect: CGRect)
{
// @FILLIN: Custom drawing code goes here.
// (Use `UIGraphicsGetCurrentContext()` where necessary.)
}
/// For compatibility, if something besides our display method asks for draw.
override func draw(_ rect: CGRect) {
internalDraw(rect)
}
Ziel c
/// Internal drawing method; naming's up to you.
- (void)internalDrawWithRect:(CGRect)rect
{
// @FILLIN: Custom drawing code goes here.
// (Use `UIGraphicsGetCurrentContext()` where necessary.)
}
/// For compatibility, if something besides our display method asks for draw.
- (void)drawRect:(CGRect)rect {
[self internalDrawWithRect:rect];
}
Und jetzt rufen myView.displayNow()
Sie einfach an, wann immer Sie es wirklich brauchen, um zu zeichnen (z. B. von einem CADisplayLink
Rückruf) . Unsere displayNow()
Methode teilt das CALayer
to mit displayIfNeeded()
, das synchron in unser zurückruft draw(_:,in:)
und das Zeichnen internalDraw(_:)
vornimmt, und aktualisiert das Bild mit dem, was in den Kontext gezeichnet wird, bevor Sie fortfahren.
Dieser Ansatz ähnelt dem oben beschriebenen von @ RobNapier, hat jedoch den Vorteil, dass displayIfNeeded()
zusätzlich aufgerufen wird setNeedsDisplay()
, wodurch er synchron ist.
Dies ist möglich, weil CALayer
s mehr Zeichenfunktionen UIView
bieten als s - Ebenen sind niedriger als Ansichten und wurden explizit für den Zweck einer hoch konfigurierbaren Zeichnung innerhalb des Layouts entworfen und (wie viele Dinge in Cocoa) so konzipiert, dass sie flexibel verwendet werden können ( als Elternklasse oder als Delegator oder als Brücke zu anderen Zeichensystemen oder nur für sich allein). Die ordnungsgemäße Verwendung des CALayerDelegate
Protokolls macht dies alles möglich.
Weitere Informationen zur Konfigurierbarkeit von CALayer
s finden Sie im Abschnitt Einrichten von Ebenenobjekten im Core Animation Programming Guide .