Ответ
Свойства frame и bounds объекта UIView описывают его прямоугольную область, но в разных системах координат.
| Свойство | Система координат | Описание | Изменение origin |
|---|---|---|---|
frame |
Система координат родительского view (superview). |
Определяет позицию и размер view относительно ее родителя. CGRect.origin — это точка (x, y) в координатах супервью. |
Перемещает view относительно родителя. |
bounds |
Внутренняя (собственная) система координат view. (0, 0) — это левый верхний угол самой view. |
Определяет внутренний размер view и видимую область ее содержимого (как «окошко»). CGRect.origin здесь называется bounds.origin. |
Сдвигает систему координат содержимого внутри view (например, для скроллинга). |
Ключевые отличия и правила:
- Зависимость:
frameявляется производным свойством. Он вычисляется на основеcenter,boundsиtransform. Прямое изменениеframeможет быть неточным, если задано вращение или скейлинг (transform). - Трансформации:
boundsне зависит отtransform. Если вы вращаете view, ееframe(описывающий ограничивающий прямоугольник) изменится, аbounds.size— останется прежним. - Использование
bounds.origin: Это мощный инструмент. Изменениеbounds.originсдвигает внутреннюю систему координат, что приводит к смещению всех дочерних view (subviews) и отрисованного содержимого (например,drawRect:). Именно так работает скроллинг вUIScrollView.
Наглядный пример:
// Создаем view размером 100x100, позиционируем ее в (50, 50) у родителя.
let greenView = UIView(frame: CGRect(x: 50, y: 50, width: 100, height: 100))
greenView.backgroundColor = .green
print(greenView.frame) // (50.0, 50.0, 100.0, 100.0) - относительно родителя
print(greenView.bounds) // (0.0, 0.0, 100.0, 100.0) - свои внутренние координаты
// Меняем bounds.origin - сдвигаем «окошко», через которое view смотрит на свое содержимое.
greenView.bounds.origin = CGPoint(x: 20, y: 20)
// Теперь внутренняя система координат greenView сдвинута.
// Точка (0,0) в системе greenView теперь соответствует точке (20,20) в его собственной геометрии.
// Это приведет к смещению всех его subviews на 20pt влево и вверх.
print(greenView.frame) // (50.0, 50.0, 100.0, 100.0) - НЕ ИЗМЕНИЛСЯ (позиция относительно родителя та же)
print(greenView.bounds) // (20.0, 20.0, 100.0, 100.0) - origin изменился
Когда что использовать:
- Используйте
frameдля позиционирования и изменения размера view внутри ее супервью. - Используйте
boundsдля работы с внутренним содержимым, его отрисовкой (drawRect:) и расположением дочерних view. Изменяйтеbounds.originдля реализации скроллинга.
Ответ 18+ 🔞
А, ну вот, опять эти ваши frame и bounds! Вечная песня, блядь. Слушай, давай без заумных мантр, а по-простому, как в жизни.
Представь себе картину в рамочке, висит у тебя на стене. Так вот, эта картина — это твой UIView, а стена — это superview, родитель.
frame— это где и какого размера эта картина висит на стене. Координаты(x: 50, y: 50)— это от левого верхнего угла стены отмерил 50 точек вправо и 50 вниз, и там её прибили.width: 100, height: 100— ну, картина квадратная, метровая, блядь. Всё относительно стены, ёпта!bounds— это внутренности самой картины, её холст. Его система координат — это её собственный левый верхний угол(0, 0). Размерbounds— это размер самого холста. Обычно он совпадает с размером рамы, но не всегда, охуенно тонкий лёд!
А теперь смотри, в чём подвох, сука:
-
frame— он вторичный, производный, как младший брат. Он высчитывается изcenter,boundsи этой вашей ебучейtransform. Если ты картину на стене повернёшь на 45 градусов (transform), то еёframeстанет описывать новый, больший прямоугольник, в который она вписана. Аbounds.sizeостанется прежним — размер холста-то не изменился! Прямо как в том анекдоте: "Я не я, и лошадь не моя". -
Волшебство
bounds.origin. Вот это, блядь, чистая магия, как у Герасима с Муму. Ты можешь сдвинутьbounds.originс(0, 0)куда-нибудь. Что произойдёт? Ты сдвигаешь не картину на стене! Ты сдвигаешь систему координат самого холста! Это как если бы ты взял и передвинул "окошко", через которое смотришь на этот холст. Все дочерние виды (subviews), которые ты на этот холст намалевал, ебанаты будут — они все дружно съедут! Именно так, сука,UIScrollViewи скроллит — он просто двигаетbounds.origin, а всё содержимое плывёт нахуй в обратную сторону. Гениально и просто, как топор!
Вот, смотри на код, не бзди:
// Вешаем зелёную картину на стену
let greenView = UIView(frame: CGRect(x: 50, y: 50, width: 100, height: 100))
greenView.backgroundColor = .green
print(greenView.frame) // (50.0, 50.0, 100.0, 100.0) - Где висит на стене
print(greenView.bounds) // (0.0, 0.0, 100.0, 100.0) - Размер её внутреннего холста
// А теперь — внимание, хуй с горы! — двигаем bounds.origin
greenView.bounds.origin = CGPoint(x: 20, y: 20)
print(greenView.frame) // (50.0, 50.0, 100.0, 100.0) - На стене-то она НЕ ДВИГАЛАСЬ! Родитель в шоке.
print(greenView.bounds) // (20.0, 20.0, 100.0, 100.0) - А вот её внутренняя система координат съехала!
// Теперь точка (0,0) на её холсте — это на самом деле точка (20,20) от её левого верхнего угла.
// Все её внутренние рисунки (subviews) поехали на 20 точек влево-вверх. Пиздец скроллинг!
Короче, запомни, как "Отче наш":
- Хочешь подвигать или растянуть вид относительно папаши (
superview) — лезь вframe(но помни проtransform, а то охуеешь). - Хочешь поковыряться во внутренностях вида, в его содержимом, или заставить его скроллиться — работай с
bounds. Особенно с этим хитрожопымbounds.origin.
Вот и вся наука, блядь. Не так страшен чёрт, как его bounds.origin.