I have the following code that allows a user to rotate an image on screen by pressing a button.
self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, rotationAmount);
This image is sitting inside of a UIScrollView which enables a user to zoom in on the photo. The problem is that when a user zooms the transform is reset. I can store the value of the transform and then re apply it after zooming but the image appears as though it is bouncing between the rotated version and non rotated version.
Is there a way to maintain the transform during zoom?
Here is the code for the scrollview
self.scrollView.minimumZoomScale=1.0;
self.scrollView.maximumZoomScale=6.0;
self.scrollView.contentSize=CGSizeMake(screenHeight, screenWidth-toolBarHeight);
self.scrollView.delegate=self;
[_scrollView setContentMode:UIViewContentModeScaleAspectFit];
[_scrollView sizeToFit];
[_scrollView setContentSize:CGSizeMake(_imageView.frame.size.width, _imageView.frame.size.height)];
I should've put this up a long time ago rather than just comment on Matt's answer, sorry.
As Matt alludes, UIScrollView works it's magic (zoom & pan) by manipulating the transform property of its content view. If you try to manipulate the transform property on the same UIView then you will be sabotaging the scrollView's efforts. You need to apply your rotation at a different level in the view hierarchy, consider rotating the scrollView itself. Best
The problem is that when a user zooms the transform is reset
Because that is what zooming is. It is the application of a scale transform to the image. That scale transform is replacing your rotation transform.
You can try implementing the zoom delegate method so as to reapply the rotation transform again and again as the user zooms. But remember to apply it relative to the scale transform or you'll lose the zoom.
Related
I'm using a variant of this code to slighty rotate a UIButton about its center:
CGFloat jiggleAngle = (-M_PI * 2.0) * (1.0 / 64.0);
self.transform = CGAffineTransformRotate(self.transform, jiggleAngle);
This code generally works as expected and rotates the button in-place, about 12 degrees counter-clockwise. However, this only works if I do not reposition the button inside my layoutSubviews method. If I do any repositioning of the button at all from its initially laid-out location, the attempt to rotate above results in the button's disappearance. If the angle I choose for rotation is an exact multiple of 90 degrees, the rotation works somehow even after a move in layoutSubviews.
I understand that my button's transform is being altered in layoutSubviews and this results in the subsequent weirdness when I attempt to rotate it with the above code. I have currently worked around this problem by placing the button I wish to rotate inside another UIView and then moving that view around as desired, but I'd like a better solution that doesn't require redoing my screen layouts.
How can I adjust/alter my button's transform after a move, so that this rotation code continues to work as expected?
The problem you are facing is that a view's frame is "undefined" if it's transform isn't the identity transform.
What you should do is use the view's center property to move it around. That works even if you've changed it's transform.
You can also apply a rotation to the view's layer instead of the view (although be aware that the layer transform is a CATransform3D, a 4x4 transformation matrix instead of a 3x3, so you need different methods to manipulate it.)
I'm trying to develop a Photo App in which when the user swipes an image, a particular part (a predefined rectangular region) of the image zooms in and scales to fit the screen's dimensions and on subsequent swipes other (predefined) parts of the image get zoomed in in a similar way.
And also the transitions to the other parts of the image should be seamless.
I'm not quite familiar with Quartz Core framework. Where should I start?
EDIT:
To aspect fit the zoomed part of the image, I did this:
if (recognizer.direction == UISwipeGestureRecognizerDirectionLeft) {
[UIView animateWithDuration:1.0 animations:^{
self.myScrollView.frame = CGRectMake((self.view.bounds.size.width - zoomWidth) / 2, (self.view.bounds.size.height - zoomHeight) / 2, zoomWidth, zoomHeight);
[self.myScrollView zoomToRect:CGRectMake(10, 10, zoomWidth, zoomHeight) animated:NO];
}];
}
I don't think you might need to use Quartz Core(which is used for custom drawing). Two ways to achieve your case come to mind. They will be more of hints since we do not know much details about the case/architecture.
UIScrollView can help you zoom in/out to the image and you can "lock" the zoom to the new region with contentSize, contentOffset, zoomScale and so on properties.
CALayer's contentsRect property can be useful since it uses only a portion of the image you supply as the layer's backing image constrained by the provided CGRect
I have a problem which is causing me a 'headache' and hope someone out there can help me.
I have a UIView with a child UIImageView presented on top, containing an image.
Using gestures, I can pan, scale and rotate that image. During this process, the anchor point may change to ensure the scale/rotate is point between the two fingers of the gesture. CGAffineTransforms are used to achieve this and it works well.
My problem is storing and recreating the transforms when I destroy and recreate the enclosing view controller.
When I leave that view, I store the transform and frame...
-(CGAffineTransform)imageViewTransform
{
return self.testImageView.transform;
}
-(CGRect)imageViewFrame
{
return self.testImageView.frame;
}
....and when I recreate that view I set the frame and transform of my imageView...
self.imageView.transform = mySavedTransform;
self.imageView.frame = mySavedFrame;
This works and I can move and stretch my image, then recreate next time in.
However, if I rotate my image, the recreated image frame at the correct angle but is stretched and not at original coordinates, so I don't get exactly what I saved.
Setting the frame before the transform has the same undesired effect on rotations.
My question is why can't I recreate the exact scaled, rotated and positioned UIImageView using the above technique?
Surely reproducing the frame and transform would have the desired effect?
Is this the usual method for doing this, or am I missing something?
Any help appreciated.
For those interest, this is sorted.
The problem was the anchor-point which was not being stored, as well as using the center for recreation of the image. So, to faithfully reproduce a transformation, it appears you need to store the center, transform and anchor.
HTH
I have a UIScrollView which displays a UIView which itself contains a small hierarchy of views. One of those sub-views is used to draw icons (their logical meaning are sticky note markers on a PDF page). Currently, the icons are zoomed along with all the other content. However, I want to draw them with the same size regardless of the current zoom (their correct position must still be maintained, of course). What's the best way to do this?
You basically have to set the transform scale of the subviews individually to match the zoom factor of the scrollView. So whenever you scroll, loop through the subviews and if the scrollview zoom factor is, say, 5.0, you'd set the transform like this:
CGFloat scaleFactor = 1.0/5.0; // 1.0 divided by the scrollview zoom factor
subview.transform = CGAffineTransformMakeScale(scaleFactor, scaleFactor);
On the plus side, it will be centered correctly, so all you have to do is set the transform and everything else should just work (you don't have to manipulate the frame).
I'm trying to rotate UIImageView for certain degrees with CGAffineTransformMakeRotation() function, but it end with imageView only rotates, but when I moved to another coordinates then imageView stretched or change height and width. I have no clue why this happens.
Here is a code:
double a = atan2(dx,dy);
bowImageView.transform = CGAffineTransformMakeRotation(a);
WHen you apply a transform to a view the geometry changes. If you wish to move that view rotated, the simplest solution is to set the transform back to CGAffineTransformIdentity, move the view and reapply the rotation.
The other way is to work out the movement based on the current rotation.....but I find the first solution easier!