view.bounds.size.height -vs- view.bounds.height -- Any Difference? - ios

I've noticed that in IOS X-Code using (Swift 4.0), I can ask for the height of a view, V, in at least these two ways:
V.bounds.size.height
and...
V.bounds.height
Is there any actual difference between these two?
I did the option-click thing (which give different definitions, but don't explain any practical difference or reason for one over the other)... and stackoverflow... but here on stackoverflow, all the results are discussing the difference between bounds and frame... which is NOT what I'm asking.

V.bounds.height is only a GET Property. You Can't set a value for this property.
Example:
self.view.bounds.height = 5
This error message results...
Cannot assign to property: 'height' is a get-only property
If you want to assign a value to this property, then you can write...
self.view.bounds.size.height = 5
So you can set value to this object. Have a look at here.

There is small difference. view.bounds.height is a shortcut. You cannot edit it :
view.bounds.height = 150 won't work, but view.bounds.size.height = 150 will.

Actually V.bounds.size.height, height have both get-set property and where as in V.bounds.height, height is only getter property and it always return you height of the rectangle.
For the getter perspective both are same.

In addition to the fact that view.bounds.height is readonly, there is another difference: if you have negative width/height, view.bounds.height will return you the normalized value (the positive one), while view.bounds.size.height will return the real value. These getters are the equivalent of the CGRectGetWidth() CGRectGetHeight() from Obj-C. All these getters from CGRect struct (widht, height, minX, minY...) are returning the normalized values of the CGRect's dimensions and they are recommended in case you want to use them in frame computations.

Related

Why does the compiler claim CGRect has no width member?

Note that I'm not trying to set the value in a CGRect. I'm mystified as to why the compiler is issuing this claim:
let widthFactor = 0.8
let oldWidth = wholeFrameView.frame.width
let newWidth = wholeFrameView.frame.width * widthFactor // Value of type '(CGRect) -> CGRect' has no member 'width'
let newWidth2 = wholeFrameView.frame.width * 0.8 // This is fine.
Width is a CGFloat where your multiplier is a Double. Explicitly declare the type of your multiplier:
let widthFactor: CGFloat = 0.8
All the dimensions of a CGRect are of type CGFloat, not Double, and because Swift is especially strict about types, you can't multiply a CGFloat by a Double.
The interesting thing though, is that both CGFloat and Double implement ExpressibleByFloatLiteral. This means that 0.8, a "float literal", can be interpreted as either a Double or a CGFloat. Without context, it's always a Double, because of how the compiler is designed. Note that this only applies to float literals like 3.14, 3e8 etc, and not to identifiers of variables.
So the expression wholeFrameView.frame.width * 0.8 is valid because the compiler sees that width is a CGFloat, so it treats 0.8 as a CGFloat as well. No problems.
On the other hand, when you declare the variable widthFactor, it is automatically given the type Double, because there aren't any more context on that line to suggest to the compiler that you want it to be any other type.
This can be fixed by directly telling the compiler that you want widthFactor to be a CGFloat:
let widthFactor: CGFloat = 0.8
Because, as others have noted, you can't multiply a Double and a CGFloat, the compiler doesn't know what you're intending.
So, instead of giving you an error about the frame property, which you currently think it's doing, it's actually making its best guess*, and giving you an error related to the frame method. No method method has a width property, so what it tells you is true.
*Of course, its best guess is not good enough, hence a human being coming here to ask a question about it. So please file a bug!
Stepping onto my soapbox: This confusion would be avoided if Apple hadn't named the method the thing it returns. The convention to prefix all such methods with get solves the problem. Some convention is important in any language with first-class functions, to disambiguate between properties and methods.
wholeFrameView.frame has no member width. Also, you need widthFactor to be of type CGFloat. Try:
let newWidth = wholeFrameView.frame.size.width * CGFloat(widthFactor)

Is it possible to rotate an image in Storyboard or do you have to do it programmatically?

Assume you have a triangle image you want to use at different angles (e.g., 180 degrees, 90 degrees).
Is it possible to rotate the triangle image within Storyboard, or do you need to do it programmatically?
You could probably create an IBDesignable & IBInspectable UIView subclass that had a rotation angle property, and applied a transform to the image it contained.
IBInspectable allows you to expose custom properties of your custom views in IB's Attributes inspector.
Making a view IBDesignable allows you to view a preview of your custom view object in IB.
Edit:
This is a very old thread, but I decided to implement a custom UIView that allows rotation, as I described. Since it's now 2021, I used Swift:
#IBDesignable class RotatableView: UIView {
#objc #IBInspectable var rotationDegrees: Float = 0 {
didSet {
print("Setting angle to \(rotationDegrees)")
let angle = NSNumber(value: rotationDegrees / 180.0 * Float.pi)
layer.setValue(angle, forKeyPath: "transform.rotation.z")
}
}
}
That yields the following in Interface Builder:
It is possible to set layer.transform.rotation.z in User Defined Runtime Attributes. Check this answer: https://stackoverflow.com/a/32150954/2650588
YES. You can this only in the Storyboard (Interface Builder) cause it's layer related properties.
Just click on your view, go to User Defined Runtime Attributes and add the key path like so:
NOTICE:
The value is in radians. For instance, to rotate 90 degrees put 1.57.
You will only see the changes during runtime.
Programmatically some thing like this can help:
//rotate rect
myImageView.transform = CGAffineTransformMakeRotation(M_PI_2); //90 degree//rotation in radians
//For 180 degree use M_PI
Or make a macro like this:
#define DEGREES_TO_RADIANS(degree) (M_PI * (degree) / 180.0)
and use this way:
CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(90));//here may be anything you want 45/90/180/270 etc.
More here : apple link

Setting UIView.transform to arbitrary translate CGAffineTransform does nothing

I have a UIView called container that I want to move (offset) using affine transfrom. This view contains UIImageView and is a subview of UICollectionViewCell.
So it should be simple:
container.transform = CGAffineTransformMakeTranslation(100, 200) //render container 100 points right and 200 points down
Instead it is very hard, because theat code does not do anything. The view is rendered excatly on the same place as if I delete that line. So I added 'print' to verify what affine translation was set:
container.transform = CGAffineTransformMakeTranslation(100, 200)
print(container.transform) //prints: CGAffineTransform(a: 1.0, b: 0.0, c: 0.0, d: 1.0, tx: 100.0, ty: 200.0)
That seems all right. So I tried rotating the container view instead with CGAffineTransformMakeRotation and it rotates the view just not around its center as it should according to documentation. I tried different combinations of translate, rotation and scale transforms just to find that the affine transformation matrixes set are OK, but attributes tx and ty seems to be ignored and a, b, c and d seems to be using different anchor point then the centre of the view (cannot say what that point is).
Any ideas on what can be causing this and how to fix it?
There must be something like auto layout messing things up for you. In the absence of outside influence, setting a view's affine transform to CGAffineTransformMakeTranslation(100, 200) will shift it right 100 points and down 200. I verified this by making a new Single View Project in Xcode and changing the viewDidLoad method in the ViewController.swift class to:
override func viewDidLoad()
{
super.viewDidLoad()
view.backgroundColor = UIColor.blueColor();
let container = UIView(frame: CGRectMake(0,0,100,100));
container.backgroundColor = UIColor.greenColor();
container.transform = CGAffineTransformMakeTranslation(100, 200);
view.addSubview(container);
}
As expected this makes the green container view appear 100 points to the right and 200 points down, even though its frame is (0,0,100,100).
So please check for auto layout and other such things that might influence the placement of this view, and if you can't find anything please post more code. Also, if your container view doesn't have a background color, please give it one so that you can see its position directly, instead of deducing its position by looking at the image view.
n.b. Setting a view's transform doesn't actually move the view itself, it just changes how/where it draws its content.

How to correctly set a circle imageView with Swift?

im trying to make a circle imageprofile, like the profile image of instagram/whatsapp. Right now my code seems to work, but i did it in 2 different ways and both works, so i want to know which one is the best
First way:
profileImageView.layer.cornerRadius = profileImageView.frame.width / 2
profileImageView.clipsToBounds = true
Second way
profileImageView.layer.cornerRadius = profileImageView.frame.width / 2
profileImageView.layer.masksToBounds = true
Also i would like if someone can explain me about "clipToBounds" and "maskToBounds", what they do. Thanks!
clipsToBounds is a boolean value that determines whether subviews are confined to the bounds of the view.
Setting this value to YES causes subviews to be clipped to the bounds of the receiver. If set to NO, subviews whose frames extend beyond the visible bounds of the receiver are not clipped. The default value is NO.
Basically, this thing plays with the view's property.
Whereas masksToBounds is a boolean indicating whether sublayers are clipped to the layer’s bounds.And this thing plays with the layer of the view.
The way that I always do it, specifically in a situation where I want to show a profile picture in my application, I use this code:
profileImage.layer.cornerRadius = self.profileImage.frame.size.width / 2;
profileImage.clipsToBounds = true;
This is what I would recommend to do!

Difference between frame.size.width and frame.width

I was writing a program in swift and just now I noticed that I can directly access a CGRect frame's width and height properties directly without using the CGSize width and height. That is I am now able to write a code like this.
#IBOutlet var myView: UIView!
override func viewDidLoad()
{
super.viewDidLoad()
var height = myView.frame.height
var height1 = myView.frame.size.height
}
In Objective C, when I tried to write the same code, the line height = view.frame.height is throwing an error. Can anyone please tell me the difference(if any) in these two lines of code.
I just looked into the CGRect structure reference. In Swift there is an extension defined which have members height and width. Please have a look at the code below
struct CGRect {
var origin: CGPoint
var size: CGSize
}
extension CGRect {
...
var width: CGFloat { get }
var height: CGFloat { get }
...
}
So that you can directly fetch height and width values from a CGRect. As you can see these are only getters, so you will get an error if you try to set these values using view.frame.height = someValue
frame is of CGRect structure, apart from its width and height have only getters, they can only be positive. From the documentation:
Regardless of whether the height is stored in the CGRect data structure as a positive or negative number, this function returns the height as if the rectangle were standardized. That is, the result is never a negative number.
However, size is of CGSize structure, from the documentation:
A CGSize structure is sometimes used to represent a distance vector, rather than a physical size. As a vector, its values can be negative. To normalize a CGRect structure so that its size is represented by positive values, call the standardized function.
So the difference is obvious.
In Objective C, when I tried to write the same code, the line height = view.frame.height is throwing an error. Can anyone please tell me the difference (if any) in these two lines of code.
CGGeometry.h defines a couple of types, among them the C struct CGRect. This struct has two members: origin and size.
That's all you can access in C (and Objective-C) using dot notation. Neither C nor Objective-C offer extensions for structs.
Swift imports the type as a Swift struct. The difference is that Swift does allow for extensions on structs. So it exposes several free C functions as extensions:
CGRectGetMinX() — CGRect.minX
CGRectGetMidX() — CGRect.midX
CGRectGetMaxX() — CGRect.maxX
CGRectGetWidth() — CGRect.width
[... same for y]
These C functions are there since ages—they just live in a dusty corner of CoreGraphics.
They are quite useful but you have to know their semantics (which differ a bit from the standard accessors): They normalise the dimensions.
This means that they convert a rect with negative width or height to a rect that covers the same area with positive size and offset origin.
let rect = CGRect(x: 0, y: 0, width: 10, height: -10)
assert(rect.width == rect.size.width) // OK
assert(rect.height == rect.size.height) // boom

Resources