Question 2
Bounds, frame, and the iOS coordinate system
Explain how bounds and frame differ, what coordinate system each uses, and how center fits in. Why does this matter when positioning subviews or applying transforms?
Follow-ups
- What happens to
framewhen you apply a rotation transform? - Why does
UIScrollViewchangebounds.origin?
Answer outline
frame and bounds are both rectangles, but they live in different coordinate spaces, and center ties them together:
- 1.Frame: a rectangle in the superview's coordinate space. Its origin is where this view's axis-aligned box sits in the parent, so it answers where the view is.
- 2.Bounds: a rectangle in the view's own coordinate space, whose size is what drawing, local hit testing, and subview layout use.
bounds.originis usually(0, 0), butUIScrollViewmoves it throughcontentOffsetto scroll content while itsframein the superview stays fixed. - 3.Center: the view's position in the superview's space, and with
boundsit determinesframe. Transforms pivot around the anchor point (the center by default), so after a rotationframegrows to the axis-aligned bounding box whileboundskeeps the untransformed size.
A subview's frame is always expressed in its superview's space. Mixing up the parent's frame space and the child's bounds space is a common source of misplaced controls and touches that land in the wrong place.
Principles
framelives in the superview's coordinate space and describes where the view is placed.boundslives in the view's own coordinate space and is what drawing, hit testing, and subview layout use.- After a transform,
frame.sizeno longer has to matchbounds.size, becauseframebecomes the bounding box of the transformed view. - Once a transform is set,
frameis undefined by contract, so read and writecenterandboundsinstead.
bounds describes local size and scroll offset, and frame describes placement in the superview:
print(view.bounds) // local: size, plus the content offset when scrolling
print(view.frame) // in the superview: position plus size
Scrolling moves bounds.origin, so different content appears under the same frame in the parent:
// contentOffset maps to bounds.origin. The frame in the superview stays put.
scrollView.contentOffset = CGPoint(x: 0, y: 300)
// scrollView.bounds.origin is now (0, 300) and scrollView.frame is unchanged
Follow-up angles
CALayermirrors this withframe,bounds, andposition. ItsanchorPointpairs withpositionto decide where transforms pivot.



