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