Restoring CGRect with Transform values from NSDictionary The Next CEO of Stack OverflowCreating a bounding box for a ViewDetecting if a CGAffineTransformed view is out of bounds of a screen/UIViewiOS Persist view transformWrong coordinates after rotating, scaling and moving one image and sending the transform to other ViewControllerMoving a UIImageViews center pointRecreating same transform on UIImageView after pan/resize/rotateHow to find UIView's frame after transform rotatingHow do I calculate the correct CGRect origin on a scaled UIView subview?Rotate image in boundsHow to ensure a UIView with a transform fills a CGRect?
Calculating discount not working
Oldie but Goldie
Why did early computer designers eschew integers?
Car headlights in a world without electricity
My ex-girlfriend uses my Apple ID to login to her iPad, do I have to give her my Apple ID password to reset it?
My boss doesn't want me to have a side project
Calculate the Mean mean of two numbers
How to show a landlord what we have in savings?
How to unfasten electrical subpanel attached with ramset
Do I need to write [sic] when including a quotation with a number less than 10 that isn't written out?
What is a typical Mizrachi Seder like?
How badly should I try to prevent a user from XSSing themselves?
How should I connect my cat5 cable to connectors having an orange-green line?
Is it okay to majorly distort historical facts while writing a fiction story?
Is it "common practice in Fourier transform spectroscopy to multiply the measured interferogram by an apodizing function"? If so, why?
MT "will strike" & LXX "will watch carefully" (Gen 3:15)?
Does int main() need a declaration on C++?
Early programmable calculators with RS-232
Can you teleport closer to a creature you are Frightened of?
Another proof that dividing by 0 does not exist -- is it right?
Finitely generated matrix groups whose eigenvalues are all algebraic
Is it correct to say moon starry nights?
What happens if you break a law in another country outside of that country?
How to pronounce fünf in 45
Restoring CGRect with Transform values from NSDictionary
The Next CEO of Stack OverflowCreating a bounding box for a ViewDetecting if a CGAffineTransformed view is out of bounds of a screen/UIViewiOS Persist view transformWrong coordinates after rotating, scaling and moving one image and sending the transform to other ViewControllerMoving a UIImageViews center pointRecreating same transform on UIImageView after pan/resize/rotateHow to find UIView's frame after transform rotatingHow do I calculate the correct CGRect origin on a scaled UIView subview?Rotate image in boundsHow to ensure a UIView with a transform fills a CGRect?
I need to be able to save the frame after transformation of a UIImageView
. In the below example, the original frame is when the image is added to the superview. The user then has the ability to rotate, scale and pan the image anywhere in the gray area (superview).
I take these images and save their coordinates to an NSDictionary (which is not the problem). The problem is that if I get the frame after the rotation, the frame is completely off. I need to be able to store the new frame with transform in the dictionary, so that when the user comes back to this view and the images are loaded, the frames and saved transformations are just like they intended.
Panning
CGPoint translation = [gestureRecognizer translationInView:[object superview]];
if (CGRectContainsPoint(self.frame, CGPointMake([object center].x + translation.x, [object center].y + translation.y)))
[object setCenter:CGPointMake([object center].x + translation.x, [object center].y + translation.y)];
[gestureRecognizer setTranslation:CGPointZero inView:[object superview]];
Rotating
self.transformRotation = CGAffineTransformRotate([[gestureRecognizer view] transform], [gestureRecognizer rotation]);
[gestureRecognizer view].transform = self.transformRotation;
if ( [gestureRecognizer rotation] != 0 )
self.rotate = [gestureRecognizer rotation];
[gestureRecognizer setRotation:0];
Scaling
self.transformScale = CGAffineTransformScale([[gestureRecognizer view] transform], [gestureRecognizer scale], [gestureRecognizer scale]);
[gestureRecognizer view].transform = self.transformScale;
if ( [gestureRecognizer scale] != 1 )
self.scale = [gestureRecognizer scale];
[gestureRecognizer setScale:1];
Using the Center point of the view keeps the image closer to the original location when it was saved, the first time it is loaded. Each time it is saved after that the position is the same, because the transform did not change during that session.
- (CGPoint)centerOnCanvas
CGPoint originalCenter = self.center;
return originalCenter;
- (CGRect)frameOnCanvas
return CGRectMake(
self.preTransformedFrame.origin.x,
self.preTransformedFrame.origin.y,
self.preTransformedFrame.size.width,
self.preTransformedFrame.size.height
);
- (CGRect)preTransformedFrame
CGAffineTransform currentTransform = self.transform;
self.transform = CGAffineTransformIdentity;
CGRect originalFrame = self.bounds;
self.transform = currentTransform;
return originalFrame;
UPDATE: Slightly off and a little larger than the original
objective-c nsdictionary cgaffinetransform cgrect cgpoint
add a comment |
I need to be able to save the frame after transformation of a UIImageView
. In the below example, the original frame is when the image is added to the superview. The user then has the ability to rotate, scale and pan the image anywhere in the gray area (superview).
I take these images and save their coordinates to an NSDictionary (which is not the problem). The problem is that if I get the frame after the rotation, the frame is completely off. I need to be able to store the new frame with transform in the dictionary, so that when the user comes back to this view and the images are loaded, the frames and saved transformations are just like they intended.
Panning
CGPoint translation = [gestureRecognizer translationInView:[object superview]];
if (CGRectContainsPoint(self.frame, CGPointMake([object center].x + translation.x, [object center].y + translation.y)))
[object setCenter:CGPointMake([object center].x + translation.x, [object center].y + translation.y)];
[gestureRecognizer setTranslation:CGPointZero inView:[object superview]];
Rotating
self.transformRotation = CGAffineTransformRotate([[gestureRecognizer view] transform], [gestureRecognizer rotation]);
[gestureRecognizer view].transform = self.transformRotation;
if ( [gestureRecognizer rotation] != 0 )
self.rotate = [gestureRecognizer rotation];
[gestureRecognizer setRotation:0];
Scaling
self.transformScale = CGAffineTransformScale([[gestureRecognizer view] transform], [gestureRecognizer scale], [gestureRecognizer scale]);
[gestureRecognizer view].transform = self.transformScale;
if ( [gestureRecognizer scale] != 1 )
self.scale = [gestureRecognizer scale];
[gestureRecognizer setScale:1];
Using the Center point of the view keeps the image closer to the original location when it was saved, the first time it is loaded. Each time it is saved after that the position is the same, because the transform did not change during that session.
- (CGPoint)centerOnCanvas
CGPoint originalCenter = self.center;
return originalCenter;
- (CGRect)frameOnCanvas
return CGRectMake(
self.preTransformedFrame.origin.x,
self.preTransformedFrame.origin.y,
self.preTransformedFrame.size.width,
self.preTransformedFrame.size.height
);
- (CGRect)preTransformedFrame
CGAffineTransform currentTransform = self.transform;
self.transform = CGAffineTransformIdentity;
CGRect originalFrame = self.bounds;
self.transform = currentTransform;
return originalFrame;
UPDATE: Slightly off and a little larger than the original
objective-c nsdictionary cgaffinetransform cgrect cgpoint
1
It's better to saveWidth
,Height
andRotation
value into UserDefaults.
– Sachin Vas
Mar 10 at 5:37
1
Could you show the code for rotate, scale and pan the image? If you useCGAffineTransform
to make them, I don't think you need to save the frame.
– trungduc
Mar 13 at 5:06
@trungduc updated.
– WrightsCS
Mar 14 at 21:24
add a comment |
I need to be able to save the frame after transformation of a UIImageView
. In the below example, the original frame is when the image is added to the superview. The user then has the ability to rotate, scale and pan the image anywhere in the gray area (superview).
I take these images and save their coordinates to an NSDictionary (which is not the problem). The problem is that if I get the frame after the rotation, the frame is completely off. I need to be able to store the new frame with transform in the dictionary, so that when the user comes back to this view and the images are loaded, the frames and saved transformations are just like they intended.
Panning
CGPoint translation = [gestureRecognizer translationInView:[object superview]];
if (CGRectContainsPoint(self.frame, CGPointMake([object center].x + translation.x, [object center].y + translation.y)))
[object setCenter:CGPointMake([object center].x + translation.x, [object center].y + translation.y)];
[gestureRecognizer setTranslation:CGPointZero inView:[object superview]];
Rotating
self.transformRotation = CGAffineTransformRotate([[gestureRecognizer view] transform], [gestureRecognizer rotation]);
[gestureRecognizer view].transform = self.transformRotation;
if ( [gestureRecognizer rotation] != 0 )
self.rotate = [gestureRecognizer rotation];
[gestureRecognizer setRotation:0];
Scaling
self.transformScale = CGAffineTransformScale([[gestureRecognizer view] transform], [gestureRecognizer scale], [gestureRecognizer scale]);
[gestureRecognizer view].transform = self.transformScale;
if ( [gestureRecognizer scale] != 1 )
self.scale = [gestureRecognizer scale];
[gestureRecognizer setScale:1];
Using the Center point of the view keeps the image closer to the original location when it was saved, the first time it is loaded. Each time it is saved after that the position is the same, because the transform did not change during that session.
- (CGPoint)centerOnCanvas
CGPoint originalCenter = self.center;
return originalCenter;
- (CGRect)frameOnCanvas
return CGRectMake(
self.preTransformedFrame.origin.x,
self.preTransformedFrame.origin.y,
self.preTransformedFrame.size.width,
self.preTransformedFrame.size.height
);
- (CGRect)preTransformedFrame
CGAffineTransform currentTransform = self.transform;
self.transform = CGAffineTransformIdentity;
CGRect originalFrame = self.bounds;
self.transform = currentTransform;
return originalFrame;
UPDATE: Slightly off and a little larger than the original
objective-c nsdictionary cgaffinetransform cgrect cgpoint
I need to be able to save the frame after transformation of a UIImageView
. In the below example, the original frame is when the image is added to the superview. The user then has the ability to rotate, scale and pan the image anywhere in the gray area (superview).
I take these images and save their coordinates to an NSDictionary (which is not the problem). The problem is that if I get the frame after the rotation, the frame is completely off. I need to be able to store the new frame with transform in the dictionary, so that when the user comes back to this view and the images are loaded, the frames and saved transformations are just like they intended.
Panning
CGPoint translation = [gestureRecognizer translationInView:[object superview]];
if (CGRectContainsPoint(self.frame, CGPointMake([object center].x + translation.x, [object center].y + translation.y)))
[object setCenter:CGPointMake([object center].x + translation.x, [object center].y + translation.y)];
[gestureRecognizer setTranslation:CGPointZero inView:[object superview]];
Rotating
self.transformRotation = CGAffineTransformRotate([[gestureRecognizer view] transform], [gestureRecognizer rotation]);
[gestureRecognizer view].transform = self.transformRotation;
if ( [gestureRecognizer rotation] != 0 )
self.rotate = [gestureRecognizer rotation];
[gestureRecognizer setRotation:0];
Scaling
self.transformScale = CGAffineTransformScale([[gestureRecognizer view] transform], [gestureRecognizer scale], [gestureRecognizer scale]);
[gestureRecognizer view].transform = self.transformScale;
if ( [gestureRecognizer scale] != 1 )
self.scale = [gestureRecognizer scale];
[gestureRecognizer setScale:1];
Using the Center point of the view keeps the image closer to the original location when it was saved, the first time it is loaded. Each time it is saved after that the position is the same, because the transform did not change during that session.
- (CGPoint)centerOnCanvas
CGPoint originalCenter = self.center;
return originalCenter;
- (CGRect)frameOnCanvas
return CGRectMake(
self.preTransformedFrame.origin.x,
self.preTransformedFrame.origin.y,
self.preTransformedFrame.size.width,
self.preTransformedFrame.size.height
);
- (CGRect)preTransformedFrame
CGAffineTransform currentTransform = self.transform;
self.transform = CGAffineTransformIdentity;
CGRect originalFrame = self.bounds;
self.transform = currentTransform;
return originalFrame;
UPDATE: Slightly off and a little larger than the original
objective-c nsdictionary cgaffinetransform cgrect cgpoint
objective-c nsdictionary cgaffinetransform cgrect cgpoint
edited Mar 15 at 19:57
WrightsCS
asked Mar 8 at 19:26
WrightsCSWrightsCS
46k21126173
46k21126173
1
It's better to saveWidth
,Height
andRotation
value into UserDefaults.
– Sachin Vas
Mar 10 at 5:37
1
Could you show the code for rotate, scale and pan the image? If you useCGAffineTransform
to make them, I don't think you need to save the frame.
– trungduc
Mar 13 at 5:06
@trungduc updated.
– WrightsCS
Mar 14 at 21:24
add a comment |
1
It's better to saveWidth
,Height
andRotation
value into UserDefaults.
– Sachin Vas
Mar 10 at 5:37
1
Could you show the code for rotate, scale and pan the image? If you useCGAffineTransform
to make them, I don't think you need to save the frame.
– trungduc
Mar 13 at 5:06
@trungduc updated.
– WrightsCS
Mar 14 at 21:24
1
1
It's better to save
Width
, Height
and Rotation
value into UserDefaults.– Sachin Vas
Mar 10 at 5:37
It's better to save
Width
, Height
and Rotation
value into UserDefaults.– Sachin Vas
Mar 10 at 5:37
1
1
Could you show the code for rotate, scale and pan the image? If you use
CGAffineTransform
to make them, I don't think you need to save the frame.– trungduc
Mar 13 at 5:06
Could you show the code for rotate, scale and pan the image? If you use
CGAffineTransform
to make them, I don't think you need to save the frame.– trungduc
Mar 13 at 5:06
@trungduc updated.
– WrightsCS
Mar 14 at 21:24
@trungduc updated.
– WrightsCS
Mar 14 at 21:24
add a comment |
1 Answer
1
active
oldest
votes
According to Apple document for UIView's transform property
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.
That's the reason why you can't get frame
after changing transform
.
As I understand, after rotating, scaling or panning you want to save current state to restore later. In my opinion, all you need to do it is saving transform
and center
of UIImageView
each time they are changed. You don't need frame
in this case.
For example, _transformTarget
is your UIImageView
, to save its current state you can use below method (Instead of saving in a NSDictionary
, I use NSUserDefaults
. You can change it to NSDictionary
)
- (void)saveCurrentState
[[NSUserDefaults standardUserDefaults] setObject:NSStringFromCGAffineTransform(_transformTarget.transform) forKey:@"_transformTarget.transform"];
[[NSUserDefaults standardUserDefaults] setObject:NSStringFromCGPoint(_transformTarget.center) forKey:@"_transformTarget.center"];
At the end of each handling gesture method, save current state by using saveCurrentState
.
- (void)handlePanGesture:(UIPanGestureRecognizer*)gesture
CGPoint translation = [gesture translationInView:self.view];
CGPoint newCenter = CGPointMake(_transformTarget.center.x + translation.x, _transformTarget.center.y + translation.y);
if (CGRectContainsPoint(self.view.frame, newCenter))
_transformTarget.center = newCenter;
[gesture setTranslation:CGPointZero inView:self.view];
[self saveCurrentState]; // Save current state when center is changed
- (void)handleRotationGesture:(UIRotationGestureRecognizer*)gesture
_transformTarget.transform = CGAffineTransformRotate(_transformTarget.transform, gesture.rotation);
gesture.rotation = 0;
[self saveCurrentState]; // Save current state when transform is changed
- (void)handlePinchGesture:(UIPinchGestureRecognizer*)gesture
_transformTarget.transform = CGAffineTransformScale(_transformTarget.transform, gesture.scale, gesture.scale);
gesture.scale = 1;
[self saveCurrentState]; // Save current state when transform is changed
Now, the information about UIImageView
is saved every time it's changed. At the next time user comes back, get info about center
and transform
from your dictionary and set them again.
- (void)restoreFromSavedState
NSString *transformString = [[NSUserDefaults standardUserDefaults] objectForKey:@"_transformTarget.transform"];
CGAffineTransform transform = transformString ? CGAffineTransformFromString(transformString) : CGAffineTransformIdentity;
NSString *centerString = [[NSUserDefaults standardUserDefaults] objectForKey:@"_transformTarget.center"];
CGPoint center = centerString ? CGPointFromString(centerString) : self.view.center;
_transformTarget.center = center;
_transformTarget.transform = transform;
Result
For more detail, you can take a look at my sample repo
https://github.com/trungducc/stackoverflow/tree/restore-view-transform
This example makes a ton of sense now, seeing that I tried to concat rotation and scale... so applying just the final transformation and saving that looks like it is working for you. I tried to simplify my code down , but I am still having some issues with the coordinates being off. Wondering if that's because the gesture code is in my object (UIImageView in your case) class, and not the superview itself. I am basing it off of the superview frame, so I dont see why that would be an issue.
– WrightsCS
Mar 15 at 18:53
@WrightsCS I’m not sure what you are talking about. Could you explain a little bit about “the coordinates being off”? I dont think that handle gestures in the object class will lead to any issue. If you want me to handle everything inside object class, I will try to make it
– trungduc
Mar 15 at 19:15
See the updated image in the original question, slightly larger images and frame is a little off, but I checked the transform and center strings when saved and when retrieved, and they are the same, so not sure why the difference!
– WrightsCS
Mar 15 at 19:55
1
Yes, of course. In my opinion, you shouldnt use autolayout in this case. I think auto layout is the reason for your problem
– trungduc
Mar 16 at 16:56
1
@WrightsCS I think you still can you constraints for canvas view. But try to calllayoutIfNeeded
before applying center and transform for objects inside to make sure canvas's frame won't be changed after (Which can lead to the problem)
– trungduc
Mar 17 at 4:56
|
show 5 more comments
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55069753%2frestoring-cgrect-with-transform-values-from-nsdictionary%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
According to Apple document for UIView's transform property
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.
That's the reason why you can't get frame
after changing transform
.
As I understand, after rotating, scaling or panning you want to save current state to restore later. In my opinion, all you need to do it is saving transform
and center
of UIImageView
each time they are changed. You don't need frame
in this case.
For example, _transformTarget
is your UIImageView
, to save its current state you can use below method (Instead of saving in a NSDictionary
, I use NSUserDefaults
. You can change it to NSDictionary
)
- (void)saveCurrentState
[[NSUserDefaults standardUserDefaults] setObject:NSStringFromCGAffineTransform(_transformTarget.transform) forKey:@"_transformTarget.transform"];
[[NSUserDefaults standardUserDefaults] setObject:NSStringFromCGPoint(_transformTarget.center) forKey:@"_transformTarget.center"];
At the end of each handling gesture method, save current state by using saveCurrentState
.
- (void)handlePanGesture:(UIPanGestureRecognizer*)gesture
CGPoint translation = [gesture translationInView:self.view];
CGPoint newCenter = CGPointMake(_transformTarget.center.x + translation.x, _transformTarget.center.y + translation.y);
if (CGRectContainsPoint(self.view.frame, newCenter))
_transformTarget.center = newCenter;
[gesture setTranslation:CGPointZero inView:self.view];
[self saveCurrentState]; // Save current state when center is changed
- (void)handleRotationGesture:(UIRotationGestureRecognizer*)gesture
_transformTarget.transform = CGAffineTransformRotate(_transformTarget.transform, gesture.rotation);
gesture.rotation = 0;
[self saveCurrentState]; // Save current state when transform is changed
- (void)handlePinchGesture:(UIPinchGestureRecognizer*)gesture
_transformTarget.transform = CGAffineTransformScale(_transformTarget.transform, gesture.scale, gesture.scale);
gesture.scale = 1;
[self saveCurrentState]; // Save current state when transform is changed
Now, the information about UIImageView
is saved every time it's changed. At the next time user comes back, get info about center
and transform
from your dictionary and set them again.
- (void)restoreFromSavedState
NSString *transformString = [[NSUserDefaults standardUserDefaults] objectForKey:@"_transformTarget.transform"];
CGAffineTransform transform = transformString ? CGAffineTransformFromString(transformString) : CGAffineTransformIdentity;
NSString *centerString = [[NSUserDefaults standardUserDefaults] objectForKey:@"_transformTarget.center"];
CGPoint center = centerString ? CGPointFromString(centerString) : self.view.center;
_transformTarget.center = center;
_transformTarget.transform = transform;
Result
For more detail, you can take a look at my sample repo
https://github.com/trungducc/stackoverflow/tree/restore-view-transform
This example makes a ton of sense now, seeing that I tried to concat rotation and scale... so applying just the final transformation and saving that looks like it is working for you. I tried to simplify my code down , but I am still having some issues with the coordinates being off. Wondering if that's because the gesture code is in my object (UIImageView in your case) class, and not the superview itself. I am basing it off of the superview frame, so I dont see why that would be an issue.
– WrightsCS
Mar 15 at 18:53
@WrightsCS I’m not sure what you are talking about. Could you explain a little bit about “the coordinates being off”? I dont think that handle gestures in the object class will lead to any issue. If you want me to handle everything inside object class, I will try to make it
– trungduc
Mar 15 at 19:15
See the updated image in the original question, slightly larger images and frame is a little off, but I checked the transform and center strings when saved and when retrieved, and they are the same, so not sure why the difference!
– WrightsCS
Mar 15 at 19:55
1
Yes, of course. In my opinion, you shouldnt use autolayout in this case. I think auto layout is the reason for your problem
– trungduc
Mar 16 at 16:56
1
@WrightsCS I think you still can you constraints for canvas view. But try to calllayoutIfNeeded
before applying center and transform for objects inside to make sure canvas's frame won't be changed after (Which can lead to the problem)
– trungduc
Mar 17 at 4:56
|
show 5 more comments
According to Apple document for UIView's transform property
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.
That's the reason why you can't get frame
after changing transform
.
As I understand, after rotating, scaling or panning you want to save current state to restore later. In my opinion, all you need to do it is saving transform
and center
of UIImageView
each time they are changed. You don't need frame
in this case.
For example, _transformTarget
is your UIImageView
, to save its current state you can use below method (Instead of saving in a NSDictionary
, I use NSUserDefaults
. You can change it to NSDictionary
)
- (void)saveCurrentState
[[NSUserDefaults standardUserDefaults] setObject:NSStringFromCGAffineTransform(_transformTarget.transform) forKey:@"_transformTarget.transform"];
[[NSUserDefaults standardUserDefaults] setObject:NSStringFromCGPoint(_transformTarget.center) forKey:@"_transformTarget.center"];
At the end of each handling gesture method, save current state by using saveCurrentState
.
- (void)handlePanGesture:(UIPanGestureRecognizer*)gesture
CGPoint translation = [gesture translationInView:self.view];
CGPoint newCenter = CGPointMake(_transformTarget.center.x + translation.x, _transformTarget.center.y + translation.y);
if (CGRectContainsPoint(self.view.frame, newCenter))
_transformTarget.center = newCenter;
[gesture setTranslation:CGPointZero inView:self.view];
[self saveCurrentState]; // Save current state when center is changed
- (void)handleRotationGesture:(UIRotationGestureRecognizer*)gesture
_transformTarget.transform = CGAffineTransformRotate(_transformTarget.transform, gesture.rotation);
gesture.rotation = 0;
[self saveCurrentState]; // Save current state when transform is changed
- (void)handlePinchGesture:(UIPinchGestureRecognizer*)gesture
_transformTarget.transform = CGAffineTransformScale(_transformTarget.transform, gesture.scale, gesture.scale);
gesture.scale = 1;
[self saveCurrentState]; // Save current state when transform is changed
Now, the information about UIImageView
is saved every time it's changed. At the next time user comes back, get info about center
and transform
from your dictionary and set them again.
- (void)restoreFromSavedState
NSString *transformString = [[NSUserDefaults standardUserDefaults] objectForKey:@"_transformTarget.transform"];
CGAffineTransform transform = transformString ? CGAffineTransformFromString(transformString) : CGAffineTransformIdentity;
NSString *centerString = [[NSUserDefaults standardUserDefaults] objectForKey:@"_transformTarget.center"];
CGPoint center = centerString ? CGPointFromString(centerString) : self.view.center;
_transformTarget.center = center;
_transformTarget.transform = transform;
Result
For more detail, you can take a look at my sample repo
https://github.com/trungducc/stackoverflow/tree/restore-view-transform
This example makes a ton of sense now, seeing that I tried to concat rotation and scale... so applying just the final transformation and saving that looks like it is working for you. I tried to simplify my code down , but I am still having some issues with the coordinates being off. Wondering if that's because the gesture code is in my object (UIImageView in your case) class, and not the superview itself. I am basing it off of the superview frame, so I dont see why that would be an issue.
– WrightsCS
Mar 15 at 18:53
@WrightsCS I’m not sure what you are talking about. Could you explain a little bit about “the coordinates being off”? I dont think that handle gestures in the object class will lead to any issue. If you want me to handle everything inside object class, I will try to make it
– trungduc
Mar 15 at 19:15
See the updated image in the original question, slightly larger images and frame is a little off, but I checked the transform and center strings when saved and when retrieved, and they are the same, so not sure why the difference!
– WrightsCS
Mar 15 at 19:55
1
Yes, of course. In my opinion, you shouldnt use autolayout in this case. I think auto layout is the reason for your problem
– trungduc
Mar 16 at 16:56
1
@WrightsCS I think you still can you constraints for canvas view. But try to calllayoutIfNeeded
before applying center and transform for objects inside to make sure canvas's frame won't be changed after (Which can lead to the problem)
– trungduc
Mar 17 at 4:56
|
show 5 more comments
According to Apple document for UIView's transform property
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.
That's the reason why you can't get frame
after changing transform
.
As I understand, after rotating, scaling or panning you want to save current state to restore later. In my opinion, all you need to do it is saving transform
and center
of UIImageView
each time they are changed. You don't need frame
in this case.
For example, _transformTarget
is your UIImageView
, to save its current state you can use below method (Instead of saving in a NSDictionary
, I use NSUserDefaults
. You can change it to NSDictionary
)
- (void)saveCurrentState
[[NSUserDefaults standardUserDefaults] setObject:NSStringFromCGAffineTransform(_transformTarget.transform) forKey:@"_transformTarget.transform"];
[[NSUserDefaults standardUserDefaults] setObject:NSStringFromCGPoint(_transformTarget.center) forKey:@"_transformTarget.center"];
At the end of each handling gesture method, save current state by using saveCurrentState
.
- (void)handlePanGesture:(UIPanGestureRecognizer*)gesture
CGPoint translation = [gesture translationInView:self.view];
CGPoint newCenter = CGPointMake(_transformTarget.center.x + translation.x, _transformTarget.center.y + translation.y);
if (CGRectContainsPoint(self.view.frame, newCenter))
_transformTarget.center = newCenter;
[gesture setTranslation:CGPointZero inView:self.view];
[self saveCurrentState]; // Save current state when center is changed
- (void)handleRotationGesture:(UIRotationGestureRecognizer*)gesture
_transformTarget.transform = CGAffineTransformRotate(_transformTarget.transform, gesture.rotation);
gesture.rotation = 0;
[self saveCurrentState]; // Save current state when transform is changed
- (void)handlePinchGesture:(UIPinchGestureRecognizer*)gesture
_transformTarget.transform = CGAffineTransformScale(_transformTarget.transform, gesture.scale, gesture.scale);
gesture.scale = 1;
[self saveCurrentState]; // Save current state when transform is changed
Now, the information about UIImageView
is saved every time it's changed. At the next time user comes back, get info about center
and transform
from your dictionary and set them again.
- (void)restoreFromSavedState
NSString *transformString = [[NSUserDefaults standardUserDefaults] objectForKey:@"_transformTarget.transform"];
CGAffineTransform transform = transformString ? CGAffineTransformFromString(transformString) : CGAffineTransformIdentity;
NSString *centerString = [[NSUserDefaults standardUserDefaults] objectForKey:@"_transformTarget.center"];
CGPoint center = centerString ? CGPointFromString(centerString) : self.view.center;
_transformTarget.center = center;
_transformTarget.transform = transform;
Result
For more detail, you can take a look at my sample repo
https://github.com/trungducc/stackoverflow/tree/restore-view-transform
According to Apple document for UIView's transform property
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.
That's the reason why you can't get frame
after changing transform
.
As I understand, after rotating, scaling or panning you want to save current state to restore later. In my opinion, all you need to do it is saving transform
and center
of UIImageView
each time they are changed. You don't need frame
in this case.
For example, _transformTarget
is your UIImageView
, to save its current state you can use below method (Instead of saving in a NSDictionary
, I use NSUserDefaults
. You can change it to NSDictionary
)
- (void)saveCurrentState
[[NSUserDefaults standardUserDefaults] setObject:NSStringFromCGAffineTransform(_transformTarget.transform) forKey:@"_transformTarget.transform"];
[[NSUserDefaults standardUserDefaults] setObject:NSStringFromCGPoint(_transformTarget.center) forKey:@"_transformTarget.center"];
At the end of each handling gesture method, save current state by using saveCurrentState
.
- (void)handlePanGesture:(UIPanGestureRecognizer*)gesture
CGPoint translation = [gesture translationInView:self.view];
CGPoint newCenter = CGPointMake(_transformTarget.center.x + translation.x, _transformTarget.center.y + translation.y);
if (CGRectContainsPoint(self.view.frame, newCenter))
_transformTarget.center = newCenter;
[gesture setTranslation:CGPointZero inView:self.view];
[self saveCurrentState]; // Save current state when center is changed
- (void)handleRotationGesture:(UIRotationGestureRecognizer*)gesture
_transformTarget.transform = CGAffineTransformRotate(_transformTarget.transform, gesture.rotation);
gesture.rotation = 0;
[self saveCurrentState]; // Save current state when transform is changed
- (void)handlePinchGesture:(UIPinchGestureRecognizer*)gesture
_transformTarget.transform = CGAffineTransformScale(_transformTarget.transform, gesture.scale, gesture.scale);
gesture.scale = 1;
[self saveCurrentState]; // Save current state when transform is changed
Now, the information about UIImageView
is saved every time it's changed. At the next time user comes back, get info about center
and transform
from your dictionary and set them again.
- (void)restoreFromSavedState
NSString *transformString = [[NSUserDefaults standardUserDefaults] objectForKey:@"_transformTarget.transform"];
CGAffineTransform transform = transformString ? CGAffineTransformFromString(transformString) : CGAffineTransformIdentity;
NSString *centerString = [[NSUserDefaults standardUserDefaults] objectForKey:@"_transformTarget.center"];
CGPoint center = centerString ? CGPointFromString(centerString) : self.view.center;
_transformTarget.center = center;
_transformTarget.transform = transform;
Result
For more detail, you can take a look at my sample repo
https://github.com/trungducc/stackoverflow/tree/restore-view-transform
answered Mar 15 at 8:23
trungductrungduc
9,04341741
9,04341741
This example makes a ton of sense now, seeing that I tried to concat rotation and scale... so applying just the final transformation and saving that looks like it is working for you. I tried to simplify my code down , but I am still having some issues with the coordinates being off. Wondering if that's because the gesture code is in my object (UIImageView in your case) class, and not the superview itself. I am basing it off of the superview frame, so I dont see why that would be an issue.
– WrightsCS
Mar 15 at 18:53
@WrightsCS I’m not sure what you are talking about. Could you explain a little bit about “the coordinates being off”? I dont think that handle gestures in the object class will lead to any issue. If you want me to handle everything inside object class, I will try to make it
– trungduc
Mar 15 at 19:15
See the updated image in the original question, slightly larger images and frame is a little off, but I checked the transform and center strings when saved and when retrieved, and they are the same, so not sure why the difference!
– WrightsCS
Mar 15 at 19:55
1
Yes, of course. In my opinion, you shouldnt use autolayout in this case. I think auto layout is the reason for your problem
– trungduc
Mar 16 at 16:56
1
@WrightsCS I think you still can you constraints for canvas view. But try to calllayoutIfNeeded
before applying center and transform for objects inside to make sure canvas's frame won't be changed after (Which can lead to the problem)
– trungduc
Mar 17 at 4:56
|
show 5 more comments
This example makes a ton of sense now, seeing that I tried to concat rotation and scale... so applying just the final transformation and saving that looks like it is working for you. I tried to simplify my code down , but I am still having some issues with the coordinates being off. Wondering if that's because the gesture code is in my object (UIImageView in your case) class, and not the superview itself. I am basing it off of the superview frame, so I dont see why that would be an issue.
– WrightsCS
Mar 15 at 18:53
@WrightsCS I’m not sure what you are talking about. Could you explain a little bit about “the coordinates being off”? I dont think that handle gestures in the object class will lead to any issue. If you want me to handle everything inside object class, I will try to make it
– trungduc
Mar 15 at 19:15
See the updated image in the original question, slightly larger images and frame is a little off, but I checked the transform and center strings when saved and when retrieved, and they are the same, so not sure why the difference!
– WrightsCS
Mar 15 at 19:55
1
Yes, of course. In my opinion, you shouldnt use autolayout in this case. I think auto layout is the reason for your problem
– trungduc
Mar 16 at 16:56
1
@WrightsCS I think you still can you constraints for canvas view. But try to calllayoutIfNeeded
before applying center and transform for objects inside to make sure canvas's frame won't be changed after (Which can lead to the problem)
– trungduc
Mar 17 at 4:56
This example makes a ton of sense now, seeing that I tried to concat rotation and scale... so applying just the final transformation and saving that looks like it is working for you. I tried to simplify my code down , but I am still having some issues with the coordinates being off. Wondering if that's because the gesture code is in my object (UIImageView in your case) class, and not the superview itself. I am basing it off of the superview frame, so I dont see why that would be an issue.
– WrightsCS
Mar 15 at 18:53
This example makes a ton of sense now, seeing that I tried to concat rotation and scale... so applying just the final transformation and saving that looks like it is working for you. I tried to simplify my code down , but I am still having some issues with the coordinates being off. Wondering if that's because the gesture code is in my object (UIImageView in your case) class, and not the superview itself. I am basing it off of the superview frame, so I dont see why that would be an issue.
– WrightsCS
Mar 15 at 18:53
@WrightsCS I’m not sure what you are talking about. Could you explain a little bit about “the coordinates being off”? I dont think that handle gestures in the object class will lead to any issue. If you want me to handle everything inside object class, I will try to make it
– trungduc
Mar 15 at 19:15
@WrightsCS I’m not sure what you are talking about. Could you explain a little bit about “the coordinates being off”? I dont think that handle gestures in the object class will lead to any issue. If you want me to handle everything inside object class, I will try to make it
– trungduc
Mar 15 at 19:15
See the updated image in the original question, slightly larger images and frame is a little off, but I checked the transform and center strings when saved and when retrieved, and they are the same, so not sure why the difference!
– WrightsCS
Mar 15 at 19:55
See the updated image in the original question, slightly larger images and frame is a little off, but I checked the transform and center strings when saved and when retrieved, and they are the same, so not sure why the difference!
– WrightsCS
Mar 15 at 19:55
1
1
Yes, of course. In my opinion, you shouldnt use autolayout in this case. I think auto layout is the reason for your problem
– trungduc
Mar 16 at 16:56
Yes, of course. In my opinion, you shouldnt use autolayout in this case. I think auto layout is the reason for your problem
– trungduc
Mar 16 at 16:56
1
1
@WrightsCS I think you still can you constraints for canvas view. But try to call
layoutIfNeeded
before applying center and transform for objects inside to make sure canvas's frame won't be changed after (Which can lead to the problem)– trungduc
Mar 17 at 4:56
@WrightsCS I think you still can you constraints for canvas view. But try to call
layoutIfNeeded
before applying center and transform for objects inside to make sure canvas's frame won't be changed after (Which can lead to the problem)– trungduc
Mar 17 at 4:56
|
show 5 more comments
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55069753%2frestoring-cgrect-with-transform-values-from-nsdictionary%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
It's better to save
Width
,Height
andRotation
value into UserDefaults.– Sachin Vas
Mar 10 at 5:37
1
Could you show the code for rotate, scale and pan the image? If you use
CGAffineTransform
to make them, I don't think you need to save the frame.– trungduc
Mar 13 at 5:06
@trungduc updated.
– WrightsCS
Mar 14 at 21:24