В UIKit, когда следует использовать свойство `bounds` у UIView?

Ответ

Свойство bounds описывает прямоугольник view в ее собственной системе координат (origin обычно (0, 0)). Его используют для операций "внутри" view.

Типичные случаи использования bounds:

  1. Рисование и расположение subviews: Все subviews позиционируются относительно bounds.origin своего супервью.
    // Добавить subview в левый верхний угол родителя
    subview.frame.origin = parentView.bounds.origin
  2. Сдвиг внутреннего содержимого (например, в UIScrollView):
    scrollView.bounds.origin.y = contentOffset // Сдвигает видимую область
  3. Обработка касаний: Проверка, попадает ли точка в границы view.
    let isInside = view.bounds.contains(touchPoint)
  4. Работа с трансформациями (transform): bounds остается неизменным при применении трансформации (например, вращении), в то время как frame может стать невалидным.

Главное отличие от frame: frame определяет положение и размер view в системе координат ее родителя и зависит от bounds, center и transform.

Ответ 18+ 🔞

А, слушай, вот эта вся хуйня с bounds и frame — классика, на которой все новички обжигаются, как дураки на морозе. Сейчас разжуем, чтобы не было мучительно больно.

Представь себе картину маслом: есть у тебя вьюха, твоя личная территория. Так вот, свойство bounds — это, блядь, твой личный чертёж этой территории, её внутренняя система координат. Точка отсчёта origin — это обычно твой левый верхний угол, твой личный нулевой километр, (0, 0). Всё, что внутри тебя, живёт по этим правилам.

Где эту штуку тыкают, чтобы не вышло пиздеца:

  1. Рисуй тут своих детей (subviews). Когда ты плодишь внутри себя сабвьюхи, ты располагаешь их относительно своего нуля, а не папиного. Хочешь прилепить к своему левому верхнему углу? Вот тебе bounds.origin.

    // Суём сабвьюху ровно в мой собственный левый верхний угол, а не куда попало
    subview.frame.origin = parentView.bounds.origin
  2. Прокрутка, ёпта! Это вообще коронный номер bounds. Смотри: у UIScrollView есть контент, который больше его самого. Когда ты скроллишь, ты же не двигаешь контент нахуй. Ты двигаешь свою собственную видимую область! То есть меняешь bounds.origin. Гениально и просто, как три копейки.

    scrollView.bounds.origin.y = contentOffset // Я сдвинул *свои* границы, и мир поплыл
  3. Ловля тачей. Тычут по экрану, а ты должен понять, попали в тебя или мимо. И проверяешь ты это в своих внутренних координатах, потому что тебе похуй, где ты в мире стоишь. Главное — попали ли в тебя.

    let isInside = view.bounds.contains(touchPoint) // В мои ли владения ткнули?
  4. Вращения, масштабы — всякая трансформационная хуйня. Вот тут вообще магия. Если ты применил transform (повернул, растянул), то frame твой может посыпаться и стать бесполезным, как прошлогодний снег. А bounds — нет, блядь! Он остаётся неизменным, как скала, потому что описывает твоё внутреннее пространство до трансформации. На него можно положиться.

А в чём, собственно, разница с frame, спросит любопытная жопа? А разница фундаментальная! frame — это взгляд со стороны. Это прямоугольник, который описывает, где ты стоишь и какого ты размера в системе координат твоего родителя. Он вычисляется на основе трёх вещей: твоих внутренних размеров (bounds.size), твоего центра (center) и твоей текущей трансформации (transform). Изменишь что-то — frame может поплыть. Bounds же — это твоя внутренняя кухня, и на ней обычно спокойно.