Cocoa: What's the difference between the frame and the bounds?
Asked Answered
U

14

633

UIView and its subclasses all have the properties frame and bounds. What's the difference?

Urnfield answered 31/7, 2009 at 0:7 Comment(4)
Understanding frame macoscope.com/blog/understanding-frameNipissing
for me the most concise explanation is here: videos.raywenderlich.com/courses/99-scroll-view-school/lessons/…Cards
There's nothing concise about a 2:30 video. I can read a sentence or two much faster than 2:30.Malloy
For me it's much more clear if I think this way: Frame = Bounds & PositionHermineherminia
V
952

The bounds of an UIView is the rectangle, expressed as a location (x,y) and size (width,height) relative to its own coordinate system (0,0).

The frame of an UIView is the rectangle, expressed as a location (x,y) and size (width,height) relative to the superview it is contained within.

So, imagine a view that has a size of 100x100 (width x height) positioned at 25,25 (x,y) of its superview. The following code prints out this view's bounds and frame:

// This method is in the view controller of the superview
- (void)viewDidLoad {
    [super viewDidLoad];

    NSLog(@"bounds.origin.x: %f", label.bounds.origin.x);
    NSLog(@"bounds.origin.y: %f", label.bounds.origin.y);
    NSLog(@"bounds.size.width: %f", label.bounds.size.width);
    NSLog(@"bounds.size.height: %f", label.bounds.size.height);

    NSLog(@"frame.origin.x: %f", label.frame.origin.x);
    NSLog(@"frame.origin.y: %f", label.frame.origin.y);
    NSLog(@"frame.size.width: %f", label.frame.size.width);
    NSLog(@"frame.size.height: %f", label.frame.size.height);
}

And the output of this code is:

bounds.origin.x: 0
bounds.origin.y: 0
bounds.size.width: 100
bounds.size.height: 100

frame.origin.x: 25
frame.origin.y: 25
frame.size.width: 100
frame.size.height: 100

So, we can see that in both cases, the width and the height of the view is the same regardless of whether we are looking at the bounds or frame. What is different is the x,y positioning of the view. In the case of the bounds, the x and y coordinates are at 0,0 as these coordinates are relative to the view itself. However, the frame x and y coordinates are relative to the position of the view within the parent view (which earlier we said was at 25,25).

There is also a great presentation that covers UIViews. See slides 1-20 which not only explain the difference between frames and bounds but also show visual examples.

Voice answered 31/7, 2009 at 0:43 Comment(10)
So won't the x,y for bounds always be 0,0 since its the location of the object in... itself. Or could you give a scenario where it wouldn't be?Urnfield
As far as I know, the origin of the bounds will always be 0,0Voice
Actually, the bounds.origin can be something besides 0,0. Use setBoundsOrigin: to move/translate the origin. See "View Geometry" in the "View Programming Guide for Cocoa" for more info.Vacancy
UIScrollView is an example where the bounds can shift to show different content regions within a view.Cannula
A small tip - using NSStringFromCGRect can save some time to log rects.Euripides
The view's frame will always contain its bounds completely. Most of the time the frame size matches the bounds size, but not always. For example, during view rotation the frame grows so it can contain the bounds. Frame size equals bounds size when bounds are at a rotation angle 0, 90, 180, and 270. Frame size is larger than bounds size when bounds are at any other angle.Tillage
Shouldn't this answer contain values before rotation and after rotation ? This would explain somehow how bounds.size could differ from frame.size (The frame.size would be bigger)Victorvictoria
@Meltemi, Here is the link for View Geometry. It's a documentation page for Mac OS X. iOS version of "View Programming Guide" does not have a page named View Geometry; it is explained in section View Geometry and Coordinate Systems.Stanch
@Urnfield The difference occurs when you modify the bounds. If you set bounds.x to 5, it will move 5 pixels horizontally from its previous location. If you set frame.x to 5, it will move to position 5 in the parent view.Observance
To quickly view NSLog of CGRect & CGPoint: NSStringFromCGRect(myView.frame)) & NSStringFromCGPoint(myView.center))Pizzicato
L
754

Short Answer

frame = a view's location and size using the parent view's coordinate system

  • Important for: placing the view in the parent

bounds = a view's location and size using its own coordinate system

  • Important for: placing the view's content or subviews within itself

Detailed Answer

To help me remember frame, I think of a picture frame on a wall. The picture frame is like the border of a view. I can hang the picture anywhere I want on the wall. In the same way, I can put a view anywhere I want inside a parent view (also called a superview). The parent view is like the wall. The origin of the coordinate system in iOS is the top left. We can put our view at the origin of the superview by setting the view frame's x-y coordinates to (0, 0), which is like hanging our picture in the very top left corner of the wall. To move it right, increase x, to move it down increase y.

To help me remember bounds, I think of a basketball court where sometimes the basketball gets knocked out of bounds. You are dribbling the ball all over the basketball court, but you don't really care where the court itself is. It could be in a gym, or outside at a high school, or in front of your house. It doesn't matter. You just want to play basketball. In the same way, the coordinate system for a view's bounds only cares about the view itself. It doesn't know anything about where the view is located in the parent view. The bounds' origin (point (0, 0) by default) is the top left corner of the view. Any subviews that this view has are laid out in relation to this point. It is like taking the basketball to the front left corner of the court.

Now the confusion comes when you try to compare frame and bounds. It actually isn't as bad as it seems at first, though. Let's use some pictures to help us understand.

Frame vs Bounds

In the first picture on the left we have a view that is located at the top left of its parent view. The yellow rectangle represents the view's frame. On the right we see the view again but this time the parent view is not shown. That's because the bounds don't know about the parent view. The green rectangle represents the view's bounds. The red dot in both images represents the origin of the frame or bounds.

Frame
    origin = (0, 0)
    width = 80
    height = 130

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

enter image description here

So the frame and bounds were exactly the same in that picture. Let's look at an example where they are different.

Frame
    origin = (40, 60)  // That is, x=40 and y=60
    width = 80
    height = 130

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

enter image description here

So you can see that changing the x-y coordinates of the frame moves it in the parent view. But the content of the view itself still looks exactly the same. The bounds have no idea that anything is different.

Up to now the width and height of both the frame and the bounds have been exactly the same. That isn't always true, though. Look what happens if we rotate the view 20 degrees clockwise. (Rotation is done using transforms. See the the documentation and these view and layer examples for more information.)

Frame
    origin = (20, 52)  // These are just rough estimates.
    width = 118
    height = 187

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

enter image description here

You can see that the bounds are still the same. They still don't know anything has happened! The frame values have all changed, though.

Now it is a little easier to see the difference between frame and bounds, isn't it? The article You Probably Don't Understand frames and bounds defines a view frame as

...the smallest bounding box of that view with respect to it’s parents coordinate system, including any transformations applied to that view.

It is important to note that if you transform a view, then the frame becomes undefined. So actually, the yellow frame that I drew around the rotated green bounds in the image above never actually exists. That means if you rotate, scale or do some other transformation then you shouldn't use the frame values any more. You can still use the bounds values, though. The Apple docs warn:

Important: If a view’s transform property does not contain the identity transform, the frame of that view is undefined and so are the results of its autoresizing behaviors.

Rather unfortunate about the autoresizing.... There is something you can do, though.

The Apple docs state:

When modifying the transform property of your view, all transformations are performed relative to the center point of the view.

So if you do need to move a view around in the parent after a transformation has been done, you can do it by changing the view.center coordinates. Like frame, center uses the coordinate system of the parent view.

Ok, let's get rid of our rotation and focus on the bounds. So far the bounds origin has always stayed at (0, 0). It doesn't have to, though. What if our view has a large subview that is too big to display all at once? We'll make it a UIImageView with a large image. Here is our second picture from above again, but this time we can see what the whole content of our view's subview would look like.

Frame
    origin = (40, 60)
    width = 80
    height = 130

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

enter image description here

Only the top left corner of the image can fit inside the view's bounds. Now look what happens if we change the bounds' origin coordinates.

Frame
    origin = (40, 60)
    width = 80
    height = 130

Bounds 
    origin = (280, 70)
    width = 80
    height = 130

enter image description here

The frame hasn't moved in the superview but the content inside the frame has changed because the origin of the bounds rectangle starts at a different part of the view. This is the whole idea behind a UIScrollView and it's subclasses (for example, a UITableView). See Understanding UIScrollView for more explanation.

When to use frame and when to use bounds

Since frame relates a view's location in its parent view, you use it when you are making outward changes, like changing its width or finding the distance between the view and the top of its parent view.

Use the bounds when you are making inward changes, like drawing things or arranging subviews within the view. Also use the bounds to get the size of the view if you have done some transfomation on it.

Articles for further research:

Apple docs

Related StackOverflow questions

Other resources

Practice yourself

In addition to reading the above articles, it helps me a lot to make a test app. You might want to try to do something similar. (I got the idea from this video course but unfortunately it isn't free.)

enter image description here

Here is the code for your reference:

import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var myView: UIView!

    // Labels
    @IBOutlet weak var frameX: UILabel!
    @IBOutlet weak var frameY: UILabel!
    @IBOutlet weak var frameWidth: UILabel!
    @IBOutlet weak var frameHeight: UILabel!
    @IBOutlet weak var boundsX: UILabel!
    @IBOutlet weak var boundsY: UILabel!
    @IBOutlet weak var boundsWidth: UILabel!
    @IBOutlet weak var boundsHeight: UILabel!
    @IBOutlet weak var centerX: UILabel!
    @IBOutlet weak var centerY: UILabel!
    @IBOutlet weak var rotation: UILabel!

    // Sliders
    @IBOutlet weak var frameXSlider: UISlider!
    @IBOutlet weak var frameYSlider: UISlider!
    @IBOutlet weak var frameWidthSlider: UISlider!
    @IBOutlet weak var frameHeightSlider: UISlider!
    @IBOutlet weak var boundsXSlider: UISlider!
    @IBOutlet weak var boundsYSlider: UISlider!
    @IBOutlet weak var boundsWidthSlider: UISlider!
    @IBOutlet weak var boundsHeightSlider: UISlider!
    @IBOutlet weak var centerXSlider: UISlider!
    @IBOutlet weak var centerYSlider: UISlider!
    @IBOutlet weak var rotationSlider: UISlider!

    // Slider actions
    @IBAction func frameXSliderChanged(sender: AnyObject) {
        myView.frame.origin.x = CGFloat(frameXSlider.value)
        updateLabels()
    }
    @IBAction func frameYSliderChanged(sender: AnyObject) {
        myView.frame.origin.y = CGFloat(frameYSlider.value)
        updateLabels()
    }
    @IBAction func frameWidthSliderChanged(sender: AnyObject) {
        myView.frame.size.width = CGFloat(frameWidthSlider.value)
        updateLabels()
    }
    @IBAction func frameHeightSliderChanged(sender: AnyObject) {
        myView.frame.size.height = CGFloat(frameHeightSlider.value)
        updateLabels()
    }
    @IBAction func boundsXSliderChanged(sender: AnyObject) {
        myView.bounds.origin.x = CGFloat(boundsXSlider.value)
        updateLabels()
    }
    @IBAction func boundsYSliderChanged(sender: AnyObject) {
        myView.bounds.origin.y = CGFloat(boundsYSlider.value)
        updateLabels()
    }
    @IBAction func boundsWidthSliderChanged(sender: AnyObject) {
        myView.bounds.size.width = CGFloat(boundsWidthSlider.value)
        updateLabels()
    }
    @IBAction func boundsHeightSliderChanged(sender: AnyObject) {
        myView.bounds.size.height = CGFloat(boundsHeightSlider.value)
        updateLabels()
    }
    @IBAction func centerXSliderChanged(sender: AnyObject) {
        myView.center.x = CGFloat(centerXSlider.value)
        updateLabels()
    }
    @IBAction func centerYSliderChanged(sender: AnyObject) {
        myView.center.y = CGFloat(centerYSlider.value)
        updateLabels()
    }
    @IBAction func rotationSliderChanged(sender: AnyObject) {
        let rotation = CGAffineTransform(rotationAngle: CGFloat(rotationSlider.value))
        myView.transform = rotation
        updateLabels()
    }

    private func updateLabels() {

        frameX.text = "frame x = \(Int(myView.frame.origin.x))"
        frameY.text = "frame y = \(Int(myView.frame.origin.y))"
        frameWidth.text = "frame width = \(Int(myView.frame.width))"
        frameHeight.text = "frame height = \(Int(myView.frame.height))"
        boundsX.text = "bounds x = \(Int(myView.bounds.origin.x))"
        boundsY.text = "bounds y = \(Int(myView.bounds.origin.y))"
        boundsWidth.text = "bounds width = \(Int(myView.bounds.width))"
        boundsHeight.text = "bounds height = \(Int(myView.bounds.height))"
        centerX.text = "center x = \(Int(myView.center.x))"
        centerY.text = "center y = \(Int(myView.center.y))"
        rotation.text = "rotation = \((rotationSlider.value))"

    }

}
Lightship answered 7/3, 2015 at 17:18 Comment(8)
It looks as though bound's width and height is redundant and an "origin" property would have been sufficient (as it was with Flash).Nicaragua
use bounds for "like drawing things or arranging subviews within the view". you mean if I have a viewController which has two buttons I should place the buttons using the view's 'bounds' of the viewController?! I've always used the view's frame...Ostracon
@Honey, I'm a little rusty on my iOS skills since I've been working on Android for the last year. I believe the root view of a View Controller fills the screen, so its frame and bounds should be the same.Lightship
Created github.com/maniramezan/FrameVsBounds.git repo based on the example app given here to help better in understanding bounds vs frame of a view.Martin
Thanks! Good explanation. An image is more valuable than 1000 wordsSheik
@IanWarburton When the view is rotated, the bound's width and height don't match that of the frame, and so are not redundant.Ideate
@Lightship "Also use the bounds to get the size of the view if you have done some transfomation on it." Is that right? I thought that transformations change the frame but not the bounds.Ideate
@EdwardBrey, In that statement I meant the size of the untransformed view. Transformations make the size of the frame undefined so you shouldn't rely on the frame width and height after you have done a transform.Lightship
E
43

try to run the code below

- (void)viewDidLoad {
    [super viewDidLoad];
    UIWindow *w = [[UIApplication sharedApplication] keyWindow];
    UIView *v = [w.subviews objectAtIndex:0];

    NSLog(@"%@", NSStringFromCGRect(v.frame));
    NSLog(@"%@", NSStringFromCGRect(v.bounds));
}

the output of this code is:

case device orientation is Portrait

{{0, 0}, {768, 1024}}
{{0, 0}, {768, 1024}}

case device orientation is Landscape

{{0, 0}, {768, 1024}}
{{0, 0}, {1024, 768}}

obviously, you can see the difference between frame and bounds

Ehrenberg answered 4/1, 2013 at 1:44 Comment(2)
this is not a true anymore (iOS 8)Clannish
#24150859Clannish
T
14

The frame is the rectangle that defines the UIView with respect to its superview.

The bounds rect is the range of values that define that NSView's coordinate system.

i.e. anything in this rectangle will actually display in the UIView.

Tavel answered 23/5, 2012 at 12:19 Comment(0)
B
13

iOS Bounds and Frame

[iOS CALayer]

UIView uses CALayer under the hood

UIView -> CALayer -> bounds, anchorPoint, position
//CALayer.position == UIView.center
  • When you create CALayer you are able to set a Frame, after that bounds, anchorPoint, position are calculated.
  • When you apply transform - bounds, anchorPoint, position are not changed but frame is changed accordingly. So frame is actually a derived property.

Apple doc

When modifying the transform property of your view, all transformations are performed relative to the center point of the view.

Bounds:

  • (x, y) - rectangle's point in it's own coordinate system to draw an internal content(subviews)
  • Width x Height - rectangle's size to draw

Frame has a direct relation with bounds, position, and transform:

  • (x, y) - rectangle's point in a parenView(superview) coordinate system
  • Width x Height - full rectangle's size which is occupied by bounds.

Take into account next items:

  • when frame's size is changed -> bounds size is changed too
  • when bounds size is changed -> frame's size is changed too
  • if you apply any view.transform(e.g. zoom, rotation, pan)(exept .identity CGAffineTransformIdentity) you should rely on CALayer.bounds(not CALayer.frame) and CALayer.position

When the value of this property is anything other than the identity transform, the value in the frame property is undefined and should be ignored.

  • view.bounds.origin is not always (0, 0). For example viewB contains viewC which is bigger then superview(viewB) in this case regulating viewB.bounds.origin we are able to regulate what will be rendered. This rectangle(point and size) will be passed into view.draw( method). This technicks also is used in UIScrollView

One more illustration to show a difference between frame and bounds. At this example:

  • viewA contains viewB
  • viewB contains viewC
  • viewC is bigger than viewB
  • View B was moved to x:72, y: 22
  • View B was rotated 45 degrees


case 4(bounds.origin is not (0, 0)):

If a view’s transform property does not contain the identity transform, the frame of that view is undefined and so are the results of its autoresizing behaviors.

viewB.autoresizingMask = [.flexibleWidth]

//case 1
//viewA.frame.size = CGSize(width: 300, height: 300)

//transform        
let radian = 45 * CGFloat.pi / 180
viewB.transform = CGAffineTransform(rotationAngle: radian)

//case 2
//viewA.frame.size = CGSize(width: 300, height: 300)

case 1 and case 2:

source code:

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    
    
    let viewA = UIView(frame: CGRect(origin: CGPoint(x: 0, y: 100), size: CGSize(width: 200, height: 200)))
    viewA.translatesAutoresizingMaskIntoConstraints = false
    viewA.backgroundColor = .gray
    self.view.addSubview(viewA)
    
    let viewBWidth: CGFloat = 20
    let viewBHeight: CGFloat = 40
    
    let viewB = UIView(frame: CGRect(origin: CGPoint(x: 72, y: 22), size: CGSize(width: viewBWidth, height: viewBHeight)))
    viewB.translatesAutoresizingMaskIntoConstraints = false
    viewB.backgroundColor = .cyan
    
    viewB.clipsToBounds = true //<- important

    //viewB.autoresizingMask = [.flexibleWidth]
    
    viewA.addSubview(viewB)

    //image.size 2560x666
    let image = UIImage(named: "icon")!
    let viewC = UIImageView(frame: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
    viewC.image = image
    
    viewB.addSubview(viewC)
    
    //case 1. rotate B
    //viewA.frame.size = CGSize(width: 300, height: 300)

    //transform
    let radian = 45 * CGFloat.pi / 180
    viewB.transform = CGAffineTransform(rotationAngle: radian)

    //case 2. Changing bounds <-> changing frame
    //viewA.frame.size = CGSize(width: 300, height: 300)
    
    //change bounds -> change frame
    //viewB.bounds.size.width = 60
    
    //change frame -> change bounds
    //viewB.frame.size.width = viewBWidth
    
//change bounds origin
    
    //case 3
    //viewB.bounds.origin.x = 0
    
    //case 4
    //viewB.bounds.origin.x = 1500
}
Barraza answered 28/3, 2020 at 17:39 Comment(0)
T
11

frame is the origin (top left corner) and size of the view in its super view's coordinate system , this means that you translate the view in its super view by changing the frame origin , bounds on the other hand is the size and origin in its own coordinate system , so by default the bounds origin is (0,0).

most of the time the frame and bounds are congruent , but if you have a view of frame ((140,65),(200,250)) and bounds ((0,0),(200,250))for example and the view was tilted so that it stands on its bottom right corner , then the bounds will still be ((0,0),(200,250)) , but the frame is not .

enter image description here

the frame will be the smallest rectangle that encapsulates/surrounds the view , so the frame (as in the photo) will be ((140,65),(320,320)).

another difference is for example if you have a superView whose bounds is ((0,0),(200,200)) and this superView has a subView whose frame is ((20,20),(100,100)) and you changed the superView bounds to ((20,20),(200,200)) , then the subView frame will be still ((20,20),(100,100)) but offseted by (20,20) because its superview coordinate system was offseted by (20,20).

i hope this helps somebody.

Trail answered 8/4, 2015 at 14:20 Comment(1)
regarding last paragraph: subView frame is relative to it's superView. changing the superView bounds to anything will not make the subView origin coincide with it's superView.Endomorphic
H
9

Let me add my 5 cents.

Frame is used by the view's parent view to place it inside the parent view.

Bounds is used by the view itself to place it's own content (like a scroll view does while scrolling). See also clipsToBounds. Bounds also can be used to zoom in/out content of the view.

Analogy:

  • Frame ~ TV screen (you place it in your room)
  • Bounds ~ Camera (camera man: zoom, move, rotate)
Hermineherminia answered 19/9, 2019 at 11:23 Comment(0)
S
7

All answers above are correct and this is my take on this:

To differentiate between frame and bounds CONCEPTS developer should read:

  1. relative to the superview (one parent view) it is contained within = FRAME
  2. relative to its own coordinate system, determines its subview location = BOUNDS

"bounds" is confusing because it gives the impression that the coordinates are the position of the view for which it is set. But these are in relations and adjusted according to the frame constants.

iPhone screen

Schistosome answered 17/4, 2019 at 19:37 Comment(0)
D
6

Frame its relative to its SuperView whereas Bounds relative to its NSView.

Example:X=40,Y=60.Also contains 3 Views.This Diagram shows you clear idea.

FRAME

BOUNDS

Dissent answered 17/12, 2015 at 7:31 Comment(0)
F
4

The answers above have very well explained the difference between Bounds and Frames.

Bounds : A view Size and Location as per its own coordinate system.

Frame : A view size and Location relative to its SuperView.

Then there is confusion that in case of Bounds the X,Y will always be "0". This is not true. This can be understood in UIScrollView and UICollectionView as well.

When bounds' x, y are not 0.
Let's assume we have a UIScrollView. We have implemented pagination. The UIScrollView has 3 pages and its ContentSize's width is three times Screen Width (assume ScreenWidth is 320). The height is constant (assume 200).

scrollView.contentSize = CGSize(x:320*3, y : 200)

Add three UIImageViews as subViews and keep a close look at the x value of frame

let imageView0 = UIImageView.init(frame: CGRect(x:0, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
let imageView1 :  UIImageView.init( frame: CGRect(x:320, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
let imageView2 :  UIImageView.init(frame: CGRect(x:640, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
scrollView.addSubview(imageView0)
scrollView.addSubview(imageView0)
scrollView.addSubview(imageView0)
  1. Page 0: When the ScrollView is at 0 Page the Bounds will be (x:0,y:0, width : 320, height : 200)

  2. Page 1: Scroll and move to Page 1.
    Now the bounds will be (x:320,y:0, width : 320, height : 200) Remember we said with respect to its own coordinate System. So now the "Visible Part" of our ScrollView has its "x" at 320. Look at the frame of imageView1.

  3. Page 2: Scroll and move to Page 2 Bounds : (x:640,y:0, width : 320, height : 200) Again take a look at frame of imageView2

Same for the case of UICollectionView. The easiest way to look at collectionView is to scroll it and print/log its bounds and you will get the idea.

Flageolet answered 7/6, 2018 at 18:16 Comment(0)
T
3

Frame vs bounds

  • If you create a view at X:0, Y:0, width:400, height:400, its frame and bounds are the same.
  • If you move that view to X:400, its frame will reflect that change but its bounds will not. Remember, the bounds is relative to the view’s own space, and internally to the view nothing has changed.
  • If you transform the view, e.g. rotating it or scaling it up, the frame will change to reflect that, but the bounds still won’t – as far as the view is concerned internally, it hasn’t changed.
  • If you change the bounds then it will change the content inside the frame because the origin of the bounds rectangle starts at a different part of the view.
Tarkington answered 12/2, 2020 at 12:2 Comment(0)
P
1

Frame is smallest rectangle which contains the view.

Bounds is exactly the view's rectangle.

enter image description here

enter image description here

Pheni answered 23/7, 2023 at 11:34 Comment(0)
B
0

Here is a great video about it (from Sean Allen):

Swift - Bounds vs. Frame - iOS Interview Question

The Frame is the position in relative to the superview coordinates: enter image description here

and the Bounds is the position relative to it's own coordinate system. enter image description here

And... it gets more tricky if the view is rotated. (watch the video!)

Beefy answered 28/8, 2022 at 9:28 Comment(0)
S
0

The frame is a computed property that defines the location and size of the view within its superview's coordinate system. The bounds.size specifies the view's original size before any transformations are applied. The bounds.origin primarily serves in the implementation of scroll views, acting as the origin of the viewport.

Here is a reverse engineered code of how the frame property is computed (from my article https://hackernoon.com/mastering-uiview-geometry-a-dive-into-uikits-foundational-class-and-geometry-concepts-for-ios):

func computeFrame(bounds: CGRect,
                  center: CGPoint,
                  anchorPoint: CGPoint,
                  tranform: CGAffineTransform) -> CGRect {

    // set the initial rectangle to bounds with origin set to (0, 0)
    let zeroOriginBounds = CGRect(origin: .zero, size: bounds.size) // 1

    // combine transformations
    let absoluteTransform = CGAffineTransform(
            translationX: -anchorPoint.x * bounds.width,
            y: -anchorPoint.y * bounds.height
        ) // align anchorPoint with coordinate system origin
        .concatenating(tranform) // apply view's transform
        .concatenating(CGAffineTransform(translationX: center.x, y: center.y)) // position the view

    // apply transform to the initial rectangle
    return CGRectApplyAffineTransform(zeroOriginBounds, absoluteTransform)
}
Silverfish answered 28/12, 2023 at 19:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.