Гарантированный возврат денег, железобетонный твердый способ заставить представление рисовать синхронно (перед возвратом к вызывающему коду) - это настроить CALayer
взаимодействия с вашим UIView
подклассом.
В своем подклассе UIView создайте displayNow()
метод, который сообщает слою « установить курс для отображения », а затем « сделать его таким »:
стриж
/// 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];
}
Также реализуйте draw(_: CALayer, in: CGContext)
метод, который будет вызывать ваш частный / внутренний метод рисования (который работает, поскольку каждый UIView
равен a CALayerDelegate
) :
стриж
/// 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();
}
И создайте свой собственный internalDraw(_: CGRect)
метод вместе с отказоустойчивым draw(_: CGRect)
:
стриж
/// 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];
}
А теперь просто звоните, myView.displayNow()
когда вам действительно-действительно нужно отрисовать (например, из CADisplayLink
обратного вызова) . Наш displayNow()
метод сообщит объекту CALayer
to displayIfNeeded()
, который синхронно обратится к нам draw(_:,in:)
и выполнит рисование internalDraw(_:)
, обновляя визуал тем, что нарисовано в контексте, прежде чем двигаться дальше.
Этот подход аналогичен описанному выше в @ RobNapier, но имеет преимущество вызова displayIfNeeded()
в дополнение к setNeedsDisplay()
, что делает его синхронным.
Это возможно, потому что CALayer
s предоставляют больше возможностей рисования, чем UIView
s, - слои являются более низкими, чем представления, и разработаны специально для целей высоконастраиваемого рисования в макете, и (как и многие вещи в Какао) спроектированы для гибкого использования ( как родительский класс, или как делегатор, или как мост к другим системам рисования, или просто самостоятельно). CALayerDelegate
Все это возможно благодаря правильному использованию протокола.
Более подробную информацию о возможности настройки CALayer
s можно найти в разделе « Настройка объектов слоя» Руководства по программированию базовой анимации .