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 CALayerInteraktionen des UIViewBenutzers 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 UIViewist 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 CADisplayLinkRückruf) . Unsere displayNow()Methode teilt das CALayerto 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 CALayers mehr Zeichenfunktionen UIViewbieten 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 CALayerDelegateProtokolls macht dies alles möglich.
Weitere Informationen zur Konfigurierbarkeit von CALayers finden Sie im Abschnitt Einrichten von Ebenenobjekten im Core Animation Programming Guide .