Drawing an image in a UIScrollView in a zoom-invariant way - ios

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).

Related

UIScrollView zoom removes transform from UIImageView

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.

Getting the same coordinates from UIScrollView whether it's zoomed or not

Is it possible to get the same coordinates from UIScrollView whether it's zoomed or not.
That is, For example, consider a plain screen of 320.0F and 480.0F.
Tap on a point; view will give me something like (60.0F, 80.0F).
Zooming-in or zooming-out on the view so that it will have either bigger or smaller zoom scale but making sure the zoomed area to contain the point that was tapped which was (60.0F, 80.0F) according to previous zoom scale.
Tap on the point again, the view will give me different coordinate value.
The Thing is, I want to have the same coordinate value whether the view is zoomed or not. The idea is simple. I want to show images zoomed & interactive without changing its coordinate. Considering an UIScrollView applied of the idea with its height of 1.0 and width of 0.66, I think there would be some pros programming this way, when making an interactive app without using OpenGL, cocos2d or whatever 3D engines out there.
Do you guys have any idea if it's supported or not? Either case, please don't wait any second to reply. Thanks
You can calculate it by yourself using content size as follows,
x = (original_Width/ width_after_zooming) * point.x
y = (original_height/ height_after_zooming) * point.y

UIView: how to "reset" transformations. CGAffineTransformScale not working as I would expect

I think my question can be summed up as how to store and reset the transform of a view. But then perhaps explaining my situation might help.
If I apply the transforms below to a view, one after another (like if I add this code to a switch or a button). I get exactly the result I would expect: the scale switches between: a view that is .55 times the size of the original view, and the view at it's original scale. Works to scale sub-views of someView too, just as I want. Ad infinitum. Perfect.
//tranformScale 1
someView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.55, 0.55 );
//tranformScale 2
someView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.0, 1.0 );
The trouble is I want to use this code (or similar) to scale a sub-view of self.view when an iOS device goes into landscape, to fit the sub-view to the landscape screen (and back up when in portrait). It almost works, but for some reason instead of outputting round values values for the frame of the view being scaled (as happens with a test using a button to call the transforms), progressively strange values are produced. Eventually, after about 4 rotations the sub-view flies off screen. I suspect it has to do with self.view changing shape, but then again, when I log the frame of self.view it's shape is very predictable.
By the way I am centering the view using autoresizingMask flexible margins, not using auto-layout. perhaps I should be centering the view with another type of calculation?
Thanks for reading!
I did this and it worked perfect.
self.imageview.transform = CGAffineTransformIdentity
(1) be sure not to set or get any frame data after applying transforms, it is unsupported and will yield unpredictable results;
(2) turn off your autoresizing mask flex margins and center like this:
view.center = CGPointMake(view.superview.bounds.size.width/2,
view.superview.bounds.size.height/2);
(take care to apply centering while view is at full size. i.e. BEFORE the transform if it is the resize transform, AFTER the transform if it is the identity transform)

Rotating a UIView; How to prevent clipping during rotation?

So let's say I have a UIView that in its standard configuration spans the full width and height of its container. For the purposes of this question, let's say that its dimensions are 320x400. Suppose that this view contains content that may be (and typically is) larger than its standard dimensions (so it scrolls through content).
Now if this UIView has a UIRotationGestureRecognizer associated with it that is used to rotate the view using its transform property, how do I ensure that its frame size/drawable area is always sufficiently large for its current orientation (by "sufficiently large" I mean that the rendered content should always extend out to the original bounds, and not be clipped prior to reaching the edge of the original bounds)? For instance, if I rotate it 90 degrees the view needs to understand that its "width" may now consume up to 400 pixels, while its height is constrained to 320 pixels.
Note that I don't want to scale the view as part of the rotation operation. Any "additional" space that becomes available due to the current rotation should be used to display additional content, if available, and not to simply display the same content at a higher zoom level.
You don't want any empty spaces to appear when rotating. The solution is to have a subview containing a background which is sufficiently large enough to cover the entire viewport during rotation. I'd say a 400 by 400 view should do. This view can either be the parent of your contentview, but that'll give you a bit of a positioning hassle.
Easier would be to add a subview on your currentview. Put the (large) background on this subview, make sure this view is at the bottom of the view stack and on your currentview put clipsToBounds=NO.
Beware though that disabling clipping can have a performance impact especially if your view hierarchy becomes complex.

Move a UIImageView after applying CGAffineTransformRotate behave incorrect

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!

Resources