How do I reset (i.e. un-zoom) a UIScrollView? - iphone

I have a UIScrollView that contains an image and a segmented control that allows the user to switch the image inside of the ScrollView. If I just swap the image out inside of the UIImageView, it will display the new image in the zoomed-in state. How do I reset the UIScrollView back to its un-zoomed-in state?

I have a detailed discussion of how (and why) UIScrollView zooming works at github.com/andreyvit/ScrollingMadness/.
(The link also contains a description of how to programmatically zoom UIScrollView, how to emulate Photo Library-style paging+zooming+scrolling, an example project and ZoomScrollView class that encapsulates some of the zooming magic.)
Quote:
UIScrollView does not have a notion of a “current zoom level”, because each subview it contains may have its own current zoom level. Note that there is no field in UIScrollView to keep the current zoom level. However we know that someone stores that zoom level, because if you pinch-zoom a subview, then reset its transform to CGAffineTransformIdentity, and then pinch again, you will notice that the previous zoom level of the subview has been restored.
Indeed, if you look at the disassembly, it is UIView that stores its own zoom level (inside UIGestureInfo object pointed to by the _gestureInfo field). It also has a set of nice undocumented methods like zoomScale and setZoomScale:animated:. (Mind you, it also has a bunch of rotation-related methods, maybe we're getting rotation gesture support some day soon.)
However, if we create a new UIView just for zooming and add our real zoomable view as its child, we will always start with zoom level 1.0. My implementation of programmatic zooming is based on this trick.

If you're not redrawing your view on the completion of the pinch zooming event, then the zoom factor is being set by the transform property of the view you return from the viewForZoomingInScrollView: delegate method. To reset this zoom, set the value of the view's transform property to CGAffineTransformIdentity.
Beware, though, that your next pinch-zooming operation will start where the previous pinch-zoom left off (that is, your new scale will be ignored). To work around this, you may need to implement some of what I describe here.

Related

Zoom the page of a view based iOS App

I have a view based application. I have to add features like pinch zoom and double tap to zoom the page(UIView) in the iOS application. Its easy to zoom a UIScrollview.
I should create a framework which has the option to pan and zoom the entire app. How do a achieve to zoom a view based application? I welcome your ideas!
The best way to do it, is to put the entire app components in one scrollview and use the zooming of the control.
The other way which is not as stable as the first one, is to scale all objects inside the UIVIEW larger or smaller depending on the pinch zoom, but keep in mind that scaling will affect the look of the entire application, so you need to adjust the position of each object accordingly.
You can create your own zoom functionalities in a UIView by using UIGestureRecognizer and CALayer transform property. Ex. scaling and change the anchorPoint base on the focus point.

iOS zoom algorithm

I am creating a graphing calculator application in OpenGL on iOS, and I would like to implement pinch zooming that works like the google maps application or uiscrollview zooming. I'm pretty sure I can't use a uiscrollview because the content of the graph is being generated dynamically.
Implementing zooming where the center of the screen is assumed to be the center of the zoom is easy, but in other cases it is not obvious to me how its being implemented. Can anyone point me in the right direction?
The view that does your custom drawing should be capable of drawing at a certain scale. When your user zooms in or out of the scroll view, send the appropriate zoom factor and let the view redraw itself. The changing bounds is not a problem. The scroll view adjusts its bounds as you pan inside, so its subviews shouldn't have any concern over the bounds of the scroll view.
Of course, you'll probably have to consider performance. For example, it may be too slow to redraw the graph at every frame as a user zooms. Instead, you may only want to redraw when the user stops zooming, which is what Maps.app does.
There are many other considerations for this problem, but that would be where I would start.
EDIT: Ah, I overlooked the OpenGL aspect. Still, with a GL layer-backed view, you still should be able to make the appropriate translations based on both the current zoom factor as well as the scroll view's bounds.

Keeping UIViews visible only within a limited area of the screen

Is it possible to make a UIView only appear inside a limited area of the screen, especially while animating? (When it reaches the boundary, it should simply cut off at the boundary point, as if it were being obscured by an object in front of it.) I need this because I have a roll-out menu comprised of UIButtons, and I don't want the menu to extend beyond the edge of the toolbar when closed. Thank you!
(Alternatively, hiding the entire UIView upon reaching the boundary would also be acceptable. I just don't know how to check for this condition without continuously querying the center property.)
You can define a clipping area for your UIVIew using the clipsToBounds property. If you are using CoreAnimation to animate your view, you may want to have a look a the maskToBounds property of CALayer objects as well (each UIVIew has a layer property of type CALayer).
From the UIView Class reference:
Normally, a subview’s visible area is
not clipped to the bounds of its
superview, but in iOS you can use the
clipsToBounds property to alter that
behavior.

What is actually changing when we zoom out a subView inside a UIScrollView?

I have a subview inside a uiscrollview. Then I zoom it out. So it becomes bigger and allows me to scroll through it.
So what is actually changing here? ContentSize of UIScrollView?
If you are not manually responding to changes in the zoom scale (like I describe in this answer), the view that you return from the -viewForZoomingInScrollView: delegate method is simply having a scaling transform applied to it by the UIScrollView. The frame size of the view is not changing, it is just being graphically transformed (which is why you see blurriness at higher scale factors).
The content size of the scrollview remains logically the same. If you check the frame of the scroll view it remains the same.
I think all that is changing is the scaling of the CGLayers. When you zoom in, it shrinks the clipping region frame smaller but then scales the CGLayer transform upwards. In other words, all the logical elements are still present it is simply choosing to draw and display a different part of it.
In the iPhone Application Programming Guide they have a good explanation about the relationship between frames, clipping regions and various transforms on views.

Zooming with a CATiledLayer in a UIScrollView

I'm implementing a map application similar to the maps app and I'm try to add zooming. I have multiple detail levels, e.g. 6, and I want to use the appropriate level for the current zoom scale. I'm using a CATiledLayer in a UIScrollView. So far I can set the min/max zoom in the UIScrollView, drawLayer gets called and I draw the appropriate tile, but this only uses my first map level. Now I want to set levelsOfDetail in the CATiledLayer so I can use the appropriate detail level.
My question is, how do I know at what level I should draw? The tileSize of CATiledLayer is always the same, and so is the clipping rect. I can see when drawLayer gets called for the new level of detail, but how to tell what level that is.
Set the levelsOfDetail and Bias up front. Then when called to draw, look at the frame of the view being zoomed by the scroll view, and compare it against the bounds. That should give you the information needed to determine what you draw. Also look at the clip path bounds to see "where" the CATiledLayer is working on next.