La manière garantie de remboursement, en béton armé solide pour forcer une vue à dessiner de manière synchrone (avant de revenir au code appelant) est de configurer les CALayer
interactions de la avec votre UIView
sous - classe.
Dans votre sous-classe UIView, créez une displayNow()
méthode qui indique au calque de « définir le cap pour l'affichage » puis de « faire en sorte »:
Rapide
/// 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()
}
Objectif 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];
}
Implémentez également une draw(_: CALayer, in: CGContext)
méthode qui appellera votre méthode de dessin privée / interne (qui fonctionne puisque tout UIView
est a CALayerDelegate
) :
Rapide
/// 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()
}
Objectif 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();
}
Et créez votre internalDraw(_: CGRect)
méthode personnalisée , avec une sécurité intégrée draw(_: CGRect)
:
Rapide
/// 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)
}
Objectif 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];
}
Et maintenant, il suffit d'appeler myView.displayNow()
chaque fois que vous en avez vraiment besoin pour dessiner (par exemple à partir d'un CADisplayLink
rappel) . Notre displayNow()
méthode indiquera CALayer
à displayIfNeeded()
, qui rappellera de manière synchrone notre draw(_:,in:)
et effectuera le dessin internalDraw(_:)
, mettant à jour le visuel avec ce qui est dessiné dans le contexte avant de continuer.
Cette approche est similaire à celle de @ RobNapier ci-dessus, mais présente l'avantage d'appeler displayIfNeeded()
en plus de setNeedsDisplay()
, ce qui la rend synchrone.
Cela est possible parce que CALayer
s exposent plus de fonctionnalités de dessin que ne le font UIView
- les couches sont de niveau inférieur aux vues et conçues explicitement dans le but de dessiner hautement configurable dans la mise en page et (comme beaucoup de choses dans Cocoa) sont conçues pour être utilisées de manière flexible ( en tant que classe parente, ou en tant que délégant, ou en tant que pont vers d'autres systèmes de dessin, ou simplement seuls). Une bonne utilisation du CALayerDelegate
protocole rend tout cela possible.
Pour plus d'informations sur la configurabilité de CALayer
s, reportez-vous à la section Configuration des objets de couche du Guide de programmation de l'animation de base .