iOS -- How to scale the UIView with left top point? - ios

I want to fix a point (left top point) and scale (zoom out) the UIView according to the point
like this image
Now I use self.transform = CGAffineTransformMakeScale( 0.7 , 0.7); to scale the UIView , But it only can scale the UIView according to the center point
Edit
I try to use set anchorPoint with (0,0) but the view position be wrong

Use anchorPoint property:
self.layer.anchorPoint = CGPointMake(0.0, 0.0);

Try to set anchorPoint of layer
container!.layer.anchorPoint = CGPoint(x: 0, y: 0)

Related

Swift: rotate imageView around left side

I have this code to rotate imageView around its axis (center of image):
transform.m34 = 1.0 / -2000.0
self.imageRevealed1.layer.transform = CATransform3DMakeRotation(CGFloat(Double.pi), 0.0, 1.0, 0.0)
But I need rotate imageView around its left side. How to do it?
You should modify the view anchorPoint before set the layer transform. Example, in your case, the anchorPoint should set CGPoint(x: 0, y: 0.5), then set transform.

View clipping after CATransform3DRotate

I'm trying to apply perspective transformation to a view (let's call it subview) that only draws a square along its frame, is centered horizontally in its superview and is 3/4 of its superview's width:
I'm using this snippet:
var rotationAndPerspectiveTransform = CATransform3DIdentity
rotationAndPerspectiveTransform.m34 = CGFloat(-1.0/280.0)
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, 30.0 * CGFloat.pi / 180.0, 1.0, 0.0, 0.0)
subview.layer.transform = rotationAndPerspectiveTransform
Which does the transformation I need, but has a weird effect — the right part of the rectangle is "clipped":
What's causing it? How can I avoid it?
Thank you!
Ah, it's a good-old bounds versus frame problem. The frame becomes wider after the transformation and doesn't fit into the bounds anymore.
As I still wanted it to be horizontally centered, this snipped did the trick:
let transformedFrame = segmentView.layer.frame
let transformedBounds = segmentView.layer.bounds
let correctedBoundsX = (transformedFrame.width - transformedBounds.width) / 2
segmentView.layer.bounds = CGRect(x: correctedBoundsX, y: transformedBounds.origin.y, width: transformedBounds.width, height: transformedBounds.height)

Transform a CGRect in Core Graphic coordinates

Is there a way to transform a CGRect with UIView system coordinates into Core Graphics coordinates, where the origin is in the lower-left corner?
Sure. You just have to subtract the y-origin and the height of the rect away from the view's height.
rect.origin.y = view.frame.size.height-(rect.origin.y+rect.size.height)
You can represent this with a CGAffineTransform like so:
CGAffineTransformMakeTranslation(0, view.size.height-((rect.origin.y*2.0)+rect.size.height))
You subtract the origin twice as you're now working with a relative value, instead of an absolute one.
However, if you only want to flip a context to work in UIView coordinates you'd want:
CGFloat ctxHeight = CGContextGetClipBoundingBox(c).size.height;
CGContextScaleCTM(c, 1, -1);
CGContextTranslateCTM(c, 0, -ctxHeight);

How to set a UIView's origin reference?

I am creating a UIImageView and adding it in a loop to my view, I set the initial frame to 0,0,1,47 and each passage of the loop I change the center of the image view to space them out.
I am always using 0 as the origin.y
The problem is the origin reference is in the centre of the image view, assuming we was in interface builder, this is equivalent to the image below.
How can I change the reference point in code ?
After reading these answers and your comments I'm not really sure what is your point.
With UIView you can set position by 2 ways:
center – It definitely says it is the center.
frame.origin – Top left corner, can't be set directly.
If you want the bottom left corner to be at x=300, y=300 you can just do this:
UIView *view = ...
CGRect frame = view.frame;
frame.origin.x = 300 - frame.size.width;
frame.origin.y = 300 - frame.size.height;
view.frame = frame;
But if you go one level deeper to magical world of CALayers (don' forget to import QuartzCore), you are more powerful.
CALayer has these:
position – You see, it don't explicitely says 'center', so it may not be center!
anchorPoint – CGPoint with values in range 0..1 (including) that specifies point inside the view. Default is x=0.5, y=0.5 which means 'center' (and -[UIView center] assumes this value). You may set it to any other value and the position property will be applied to that point.
Example time:
You have a view with size 100x100
view.layer.anchorPoint = CGPointMake(1, 1);
view.layer.position = CGPointMake(300, 300);
Top left corner of the view is at x=200, y=200 and its bottom right corner is at x=300, y=300.
Note: When you rotate the layer/view it will be rotated around the anchorPoint, that is the center by default.
Bu since you just ask HOW to do specific thing and not WHAT you want to achieve, I can't help you any further now.
The object's frame includes its position in its superview. You can change it with something like:
CGRect frame = self.imageView.frame;
frame.origin.y = 0.0f;
self.imageView.frame = frame;
If I am understanding you correctly, you need to set the frame of the image view you are interested in moving. This can be done in the simple case like this:
_theImageView.frame = CGRectMake(x, y, width, height);
Obviously you need to set x, y, width, and height yourself. Please also be aware that a view's frame is in reference to its parent view. So, if you have a view that is in the top left corner (x = 0, y = 0), and is 320 points wide and 400 points tall, and you set the frame of the image view to be (10, 50, 100, 50) and then add it as a subview of the previous view, it will sit at x = 10, y = 50 of the parent view's coordinate space, even though the bounds of the image view are x = 0, y = 0. Bounds are in reference to the view itself, frame is in reference to the parent.
So, in your scenario, your code might look something like the following:
CGRect currentFrame = _theImageView.frame;
currentFrame.origin.x = 0;
currentFrame.origin.y = 0;
_theImageView.frame = currentFrame;
[_parentView addSubview:_theImageView];
Alternatively, you can say:
CGRect currentFrame = _theImageView.frame;
_theImageView.frame = CGRectMake(0, 0, currentFrame.size.width, currentFrame.size.height);
[_parentView addSubview:_theImageView];
Either approach will set the image view to the top left of the parent you add it to.
I thought I would take a cut at this in Swift.
If one would like to set a views position on the screen by specifying the coordinates to an origin point in X and Y for that view, with a little math, we can figure out where the center of the view needs to be in order for the origin of the frame to be located as desired.
This extension uses the frame of the view to get the width and height.
The equation to calculate the new center is almost trivial. See the below extension :
extension CGRect {
// Created 12/16/2020 by Michael Kucinski for anyone to reuse as desired
func getCenterWhichPlacesFrameOriginAtSpecified_X_and_Y_Coordinates(x_Position: CGFloat, y_Position: CGFloat) -> CGPoint
{
// self is the CGRect
let widthDividedBy2 = self.width / 2
let heightDividedBy2 = self.height / 2
// Calculate where the center needs to be to place the origin at the specified x and y position
let desiredCenter_X = x_Position + widthDividedBy2
let desiredCenter_Y = y_Position + heightDividedBy2
let calculatedCenter : CGPoint = CGPoint(x: desiredCenter_X, y: desiredCenter_Y)
return calculatedCenter // Using this point as the center will place the origin at the specified X and Y coordinates
}
}
Usage as shown below to place the origin in the upper left corner area, 25 pixels in :
// Set the origin for this object at the values specified
maskChoosingSlider.center = maskChoosingSlider.frame.getCenterWhichPlacesFrameOriginAtSpecified_X_and_Y_Coordinates(x_Position: 25, y_Position: 25)
If you want to pass a CGPoint into the extension instead of X and Y coordinates, that's an easy change you can make on your own.

Scale a UIView Horizontally

I'm trying to scale a view Horizontally but i'm not getting the results i expected.
view.bounds = CGRectMake(view.bounds.origin.x, view.bounds.origin.y , view.bounds.size.width * scaleX, view.bounds.size.height );
view.center = CGPointMake(view.bounds.origin.x, view.center.y);
As you can see at the code above, i want to scale the view just to the right side. This is why i changed the center of the view.
The problem is that the view stills scaling to both sides!
I did the same logic to scale another UIView vertically and got the result i expected.
Just found the problem.
when setting certer, the new point must be relative to frame, not bounds.
so, i get the code:
view.center = CGPointMake(-view.frame.origin.x, view.center.y);
Hope it helps somebody..
Thx for help
If the origin of your view's frame is in the top-left (which is the default), increasing the width of your view should scale it to the right only.
This should work:
view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width * scaleX, view.frame.size.height);
You do not need to adjust the origin/center point to scale only to the right.
Try using an affine transform instead:
view.transform = CGAffineTransformMakeScale(scaleX, 1)
And then setting the center.

Resources