Il modo con rimborso garantito, cemento armato-solido per forzare una vista a disegnare in modo sincrono (prima di tornare al codice chiamante) è configurare le CALayerinterazioni di con la tua UIViewsottoclasse.
Nella tua sottoclasse UIView, crea un displayNow()metodo che dica al livello di " impostare la rotta per la visualizzazione ", quindi di " renderla tale ":
veloce
/// 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()
}
Objective-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];
}
Implementa anche un draw(_: CALayer, in: CGContext)metodo che chiamerà il tuo metodo di disegno privato / interno (che funziona poiché ogni UIViewè a CALayerDelegate) :
veloce
/// 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()
}
Objective-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();
}
E crea il tuo internalDraw(_: CGRect)metodo personalizzato , insieme a fail-safe draw(_: CGRect):
veloce
/// 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)
}
Objective-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];
}
E ora chiama semplicemente myView.displayNow()ogni volta che ne hai davvero bisogno per disegnare (come da una CADisplayLinkrichiamata) . Il nostro displayNow()metodo dirà al CALayerto displayIfNeeded(), che richiamerà in modo sincrono nel nostro draw(_:,in:)e farà il disegno internalDraw(_:), aggiornando l'immagine con ciò che è disegnato nel contesto prima di andare avanti.
Questo approccio è simile a quello di @ RobNapier sopra, ma ha il vantaggio di chiamare displayIfNeeded()in aggiunta a setNeedsDisplay(), il che lo rende sincrono.
Ciò è possibile perché CALayers espone più funzionalità di disegno rispetto a UIViews: i livelli sono di livello inferiore rispetto alle viste e progettati esplicitamente allo scopo di disegnare altamente configurabili all'interno del layout e (come molte cose in Cocoa) sono progettati per essere utilizzati in modo flessibile ( come classe genitore, o come delegante, o come ponte verso altri sistemi di disegno, o semplicemente da soli). Il corretto utilizzo del CALayerDelegateprotocollo rende tutto questo possibile.
Ulteriori informazioni sulla configurabilità di CALayers sono disponibili nella sezione Configurazione di oggetti livello della Guida alla programmazione dell'animazione di base .