Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Всегда ли frame и bounds одинаковы?
Нет, frame и bounds UIView далеко не всегда одинаковы. Это одно из фундаментальных различий в системе координат iOS и UIKit, и понимание этой разницы критически важно для корректного позиционирования, трансформаций и отрисовки view.
Ключевое различие в системе координат
Основная разница заключается в точке отсчета (origin) и назначении этих свойств:
frame(CGRect): Описывает положение и размер view в системе координат ее супервью (родителя). Егоorigin(например,(x: 20, y: 50)) отвечает на вопрос: "Где левый верхний угол этой view расположен относительно левого верхнего угла ее родителя?".bounds(CGRect): Описывает положение и размер view в ее собственной внутренней системе координат. По умолчанию егоoriginравен(0, 0). Он отвечает на вопрос: "Какая видимая часть внутреннего содержимого этой view (например, ее subviews или рисунок)?"originbounds можно менять, чтобы "прокручивать" содержимое.
Когда frame и bounds РАЗНЫ? (Типичные случаи)
- Вращение и трансформации (Affine Transforms)
Это самый важный и показательный случай. Свойство `frame` становится неопределенным (`undefined`), если к view применена не-идентичная трансформация вращения или масштабирования. Его вычисление является затратной операцией. `bounds` и `center` при этом остаются валидными и используются для корректной работы с трансформированными view.
```swift
let view = UIView(frame: CGRect(x: 50, y: 50, width: 100, height: 100))
view.transform = CGAffineTransform(rotationAngle: .pi / 6) // Поворот на 30°
// После трансформации:
print(view.frame) // Может показать, например, (35.0, 35.0, 141.0, 141.0)
print(view.bounds) // Останется (0.0, 0.0, 100.0, 100.0)
// frame изменился, чтобы описать bounding box повернутой view.
// bounds не изменился, так как внутренняя геометрия view та же.
```
2. Изменение origin свойства bounds
Это активно используется в `UIScrollView` и ее подклассах (`UITableView`, `UICollectionView`). Сдвигая `bounds.origin`, мы сообщаем view, какая часть ее внутреннего контента должна быть отрисована в левом верхнем углу ее видимой области.
```swift
let scrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: 320, height: 568))
scrollView.contentSize = CGSize(width: 1000, height: 568)
// При прокрутке вправо на 150 точек:
scrollView.bounds.origin = CGPoint(x: 150, y: 0)
print(scrollView.frame) // Останется (0.0, 0.0, 320.0, 568.0) - положение на экране не изменилось
print(scrollView.bounds) // Станет (150.0, 0.0, 320.0, 568.0) - видимая область сместилась
```
3. Вложенность view (без трансформаций)
Даже в простом случае, если view не находится в самом левом верхнем углу родителя, `frame.origin` и `bounds.origin` будут разными.
```swift
let parentView = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 800))
let childView = UIView(frame: CGRect(x: 100, y: 200, width: 150, height: 150))
parentView.addSubview(childView)
print(childView.frame) // (100.0, 200.0, 150.0, 150.0) - относительно parentView
print(childView.bounds) // (0.0, 0.0, 150.0, 150.0) - относительно себя
```
Когда frame и bounds МОГУТ БЫТЬ ОДИНАКОВЫ?
Единственный случай — когда view является корневой и не имеет трансформаций, и ее bounds.origin не менялся. Тогда:
frame.originзадается относительно супервью (которого нет, обычно это координаты окна).bounds.originпо умолчанию(0, 0).
Но даже в этом случае их семантика разная: frame описывает положение в родительской системе координат, а bounds — внутреннюю геометрию. Их числовое равенство — ситуативное совпадение, а не правило.
Практическое правило для разработчика
- Используйте
frame, когда вам нужно:
* **Расположить или изменить размер view относительно ее супервью.**
* Получить **bounding box** view на экране (если нет трансформаций).
- Используйте
bounds, когда вам нужно:
* **Расположить что-либо внутри view** (например, добавить subview или нарисовать).
* Работать с **прокруткой** (`UIScrollView`).
* Корректно работать с view, к которой применены **трансформации** (вместе с `center`).
* Получить реальный внутренний размер view, не зависящий от трансформаций.
Таким образом, различие между frame и bounds — это не баг, а фича, обеспечивающая гибкость и мощь системы отрисовки UIKit. Их неодинаковость — это норма и ожидаемое поведение в большинстве нетривиальных случаев.