-layoutSubviews
вызывается из -layoutIfNeeded
, если был установлен флаг «Требуется макет» (используется -setNeedsLayout
или автоматически при изменении границ вида). Используйте его для позиционирования вашего вида [ РЕДАКТИРОВАТЬ: Используйте его для позиционирования подпредставлений ].
-drawRect:
вызывается с -displayIfNeeded
, если был установлен флаг «display display» (с использованием -setNeedsDisplay
или автоматически, если вы установили view.contentMode = UIViewContentModeRedraw
).
Оба -layoutIfNeeded
и -displayIfNeeded
автоматически вызываются UIKit / CoreAnimation перед тем, как что-либо выводится на экран; вам редко нужно звонить им напрямую.
Вы можете расположить свои подпредставления в -drawRect:
(вы даже можете добавить подпредставления!), Но это неразумно:
- По умолчанию
-setNeedsDisplay
не вызывается автоматически при изменении границ.
- Реализация
-drawRect:
снижает производительность (UIKit / CoreAnimation должен создать для вас растровый графический контекст); делайте это только в том случае, если вам нужно выполнить пользовательский рисунок.
- Вам нужно перерисовать представление в
-drawRect:
. Рисование стоит дорого. Перемещение взглядов дешево.
- UIKit / CoreAnimation, вероятно, выполняет этап макета, за которым следует этап рисования. CoreAnimation может использовать информацию макета, чтобы решить, какие виды нужно рисовать (например, он может игнорировать виды, скрытые непрозрачными подпредставлениями, внеэкранными представлениями или подпредставлениями за пределами представления clipsToBounds = YES; или он может рисовать только под-прямоугольник большой вид). Если вы перемещаете виды во время прохождения рисования, CoreAnimation может отображать их неправильно.
РЕДАКТИРОВАТЬ: И еще некоторые подробности, когда я не сплю:
В чем разница между «показом» и «отрисовкой»? Отображение осуществляется с помощью -[CALayer display]
; реализация по умолчанию (приблизительно)
- Если представитель уровня отвечает на
-displayLayer:
, позвоните [self.delegate displayLayer:self]
. -displayLayer:
должен установить layer.content
на (например) CGImage,
- В противном случае, если делегат уровня отвечает на
-drawLayer:inContext:
, настройте контекст на основе растрового изображения, вызовите [self.delegate drawLayer:self inContext:context]
и сохраните вывод в layer.content
(вывод на самом деле является CABackingStore, который предположительно является частным API )
- В противном случае не изменяйте
layer.content
.
Представление является делегатом слоя, поэтому вы можете вместо этого реализовать -[MyView displayLayer:]
и делать интересные вещи, такие как
self.layer.contents = (id)([UIImage imageNamed:@"foo"].CGImage)
(это примерно то, что делает UIImageView)
- Нет, чтобы предотвратить любой "рисунок". Это может быть полезно, если вы подклассами, например UIToolbar и хочу дать ему прозрачный фон. (Это также предотвращает создание CGContext / CABackingStore.)
- Перемещать подпредставления без снижения производительности (но это по-прежнему не очень хорошая идея по вышеуказанным причинам).