A maneira garantida de devolução do dinheiro e sólido de concreto armado de forçar uma visualização a desenhar de forma síncrona (antes de retornar ao código de chamada) é configurar as CALayer
interações de com sua UIView
subclasse.
Em sua subclasse UIView, crie um displayNow()
método que diga à camada para " definir o curso para exibição " e " torná-lo assim ":
Rápido
/// 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];
}
Implemente também um draw(_: CALayer, in: CGContext)
método que chamará seu método de desenho privado / interno (que funciona já que todo UIView
é um CALayerDelegate
) :
Rápido
/// 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 crie seu internalDraw(_: CGRect)
método personalizado , junto com a prova de falhas draw(_: CGRect)
:
Rápido
/// 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 agora apenas chame myView.displayNow()
sempre que você realmente precisar para desenhar (como em um CADisplayLink
retorno de chamada) . Nosso displayNow()
método dirá o CALayer
para displayIfNeeded()
, que irá chamar de volta sincronizadamente o nosso draw(_:,in:)
e desenhar internalDraw(_:)
, atualizando o visual com o que é desenhado no contexto antes de prosseguir.
Essa abordagem é semelhante à de @RobNapier acima, mas tem a vantagem de chamar displayIfNeeded()
além de setNeedsDisplay()
, o que a torna síncrona.
Isso é possível porque CALayer
s expõe mais funcionalidade de desenho do que UIView
s - as camadas são de nível inferior do que as vistas e são projetadas explicitamente para o propósito de desenho altamente configurável dentro do layout e (como muitas coisas no Cocoa) são projetadas para serem usadas de forma flexível ( como uma classe pai, ou como um delegador, ou como uma ponte para outros sistemas de desenho, ou apenas por conta própria). O uso adequado do CALayerDelegate
protocolo torna tudo isso possível.
Mais informações sobre a configurabilidade de CALayer
s podem ser encontradas na seção Setting Up Layer Objects do Core Animation Programming Guide .