Sorry for long winded post.
I am trying to understand UIScrollView and running into very simple problem.
I am creating a scroll view
I am making this view 1.5 size larger then normal size
Using UIScrollView I expect to see some edge elements of view out of bounds, but should be able to pan the view therefore bringing missing elements back to the visible area.
However I am seeing that I can't just pan/scroll view anyway I want, instead view always wants to scroll up, as soon as move away my finger from the screen (touch end event).
I am not handling any touches, etc - I just want to understand why does not scaled view stay put where I scroll it?
CGRect viewFrame = self.view.frame ;
viewFrame.size.width *= 1.5;
viewFrame.size.height *= 1.5;
CGSize mySize = viewFrame.size;
[ ((UIScrollView *) self.view) setContentSize: mySize];
self.view.transform = CGAffineTransformMakeScale(1.5, 1.5);
What I really trying to accomplish is something similar to Number on iPad (the same code will work on iPhone):
There is a view with lots of controls
on it (order entry form)
User can zoom into the entire form so all elements look bigger
user can pan the form therefore bringing various elements into the visible area of the screen.
It seems that UIScrollView can should be able to handle zoom and pan actions (for now I am using Affine Transform to zoom in to the order entry form and iPad)
Thanks
When you transform a view, you transform its internal coordinate system as well. This means that if you scale a view, the view still "thinks" it is the same size it was before the scale because its coordinate units scaled as well.
For example, if you have an image view that has a size of (50,50) and you transform it so that it covers (200,200) on the screen, when you ask the image view its size it will report that its size is still (50,50).
Scrollviews are unusual types of views because they have understand their absolute size relative to physical device screen in order to work properly. When you transform their coordinate system, they lose that connection to the physical device screen and can no longer function properly. This is what you are seeing.
I haven't done this but I'm pretty sure to create the illusion of a zoom in a scrollview, you increase the frame of the scrollview and then transform its subviews (or transform the subviews and then increase the frame of the scrollview to contain the new subview size.) That is the only way to keep the scrollview in sync with the physical device screen.
Related
I have a zoomable UIScrollView which contains a custom drawn view (two circles). When the view is zoomed, I want to know where the centres of the circles lie, wrt the App's window. Consider these steps:
The view at 1X
The view zoomed at an arbitrary level, with the pinch focused on the first circle
The view zoomed at an arbitrary level, with the pinch focused on the top right corner
What I am meaning to ask is, if I were to lay another view containing a circle on top of the scroll view such that the circle in this view is concentric (need not be of the same size) with the smaller circle in the scroll view's view, where should the centre of the new circle be located?
When using UIView's coordinate conversion methods it is not relevant that you custom view is embedded in a scroll view:
MyCustomCircleView *circleView;
CGPoint centerInLocalCoordinates = circleView.centerOfACircle;
CGPoint centerInWindowCoordinates = [circleView convertPoint:centerInLocalCoordinates
toView:nil];
Maybe window coordinates are not what you are looking for. Remember that the window's coordinate space is always in portrait orientation and with the home button at the bottom. When holding the device in landscape orientation, your coordinates are (of course) rotated.
It might be easier to convert to a superview's coordinates, for example your view controller's view's coordinate space.
Did you draw the circles? Some combination of scrollView.contentOffset, scrollView.contentSize, and scrollView.zoomScale is what you want. You can walk back the translation and scaling using those values.
This is a general question to a specific problem.
I am using a UIScrollView in an app that displays photographs. on iOS < 4.0, zooming works great. the same app running on iOS 4.0.x has problems zooming. specifically, if the image does not fill the view (and black bands appear at top/bottom), the first zoom is jerky and garbage data is shown on the bottom of the screen.
the source code to analyze is way to complex and spread out to adequately share here. Can anyone suggest any areas to look at that might cause this strange behavior?
thanks!
Mark
edit: here's the code from the double tap handler (borrowed from the tapDetectingImageView sample code):
- (void)tapDetectingImageView:(TapDetectingImageView *)view gotDoubleTapAtPoint:(CGPoint)tapPoint {
// double tap zooms in
float newScale = [self zoomScale] * ZOOM_STEP;
CGRect zoomRect = [self zoomRectForScale:newScale withCenter:tapPoint];
[self zoomToRect:zoomRect animated:YES];
}
I can force the weirdness if I change the animated parameter in the call to zoomToRect. when animated is NO, my image becomes 2 images superimposed one on top of the other. the bottom image is the original zoom level, the top image is the new zoom level. if I swipe the screen to pan, the image is refreshed. It's almost as if a call to layoutSubviews or DrawRect is not getting called.
This may or may not be related, but the way that UIScrollView dealt with scale factors changed in an undocumented way in iPhone OS 3.2+.
Previously, if you used -scrollViewDidEndZooming:withView:atScale: to re-render your content by applying the identity transform to the view and then redrawing your image sharply at the new scale factor, UIScrollView would ignore this and keep handing you absolute scale factors based on the initial size of the view.
On iPhone OS 3.2+, UIScrollView now gives you a relative scale factor based on the last time you reset the transform of the content view to be the identity transform. This can lead to significant scaling differences between the various OS versions.
I a have a following line of code invoked after a touch gesture has completed:
CGRect parentBounds = self.view.bounds;
CGRect parentFrame = self.view.frame;
when iPad is placed in a vertical way both parentFrame and parentBounds have similar dimensions of w:768 h:1004 (or something close to that), but when I rotate parentBounds is 1024x748 while parentFrame is 768x1024.
Is this behavior normal? I thought I understood the concepts beetwen frames and bounds (and how they relate to each other)... but now I am really confused.
Could anyone explain what is happening with frame and bounds of a window (superview) when rotation occurs?
The window does not change orientation; the root view does. It does this by applying a view transform (self.view.transform). You're not supposed to call frame if transform is not CGAffineTransformIdentity.
This is not a complete answer, but might help if you don't get something better: When the device is rotated, the top-level window's frame does not change. Instead, a transform gets applied that rotates everything 90 degrees (or 180 degrees), and then the subviews will get resized to fit in the new coordinate system.
From Apple's PhotoScroller sample code:
We have to use our paging scroll view's bounds, not frame, to calculate the page placement. When the device is in landscape orientation, the frame will still be in portrait because the pagingScrollView is the root view controller's view, so its frame is in window coordinate space, which is never rotated. Its bounds, however, will be in landscape because it has a rotation transform applied.
In short, the view's frame is not affected by device rotations, but its bounds is.
I'm trying to understand how UIScrollView works for zooming.
I was trying to rotate a UIImageView within a zoomed UIScrollView and I ended up with weird sizes, my centering in the scrollview not working anymore.
I solved the problem by setting the zoomScale to 1.0 before doing the rotation, and then by resetting it back to the previous value once the transformation was done.
I was wondering what was the impact of the UIScrollView on its subviews. Does it change their sizes, their positions. Or is it simply the UIScrollView that handles the zooming and the drawing of the zoomed subviews.
I realise that is an old question, but I thought I'd add additional information for those still arriving here like myself.
The scroll view manages its contents view, it zooms by adding tranformations to the content. So, for an image when you zoom in, it uses a tranformation to scale the image to the required zoom level.
When you are panning/scrolling a ScrollView, it changes the zoom level and origin positions to move the content around. So the content may well be larger than the scrollview itself. It clips the content at the scrollviews bounds and just adjusts this origin position.
The central notion of a UIScrollView object (or, simply, a scroll view) is that it is a view whose origin is adjustable over the content view. It clips the content to its frame, which generally (but not necessarily) coincides with that of the application’s main window. A scroll view tracks the movements of fingers and adjusts the origin accordingly. The view that is showing its content “through” the scroll view draws that portion of itself based on the new origin, which is pinned to an offset in the content view. The scroll view itself does no drawing except for displaying vertical and horizontal scroll indicators. The scroll view must know the size of the content view so it knows when to stop scrolling; by default, it “bounces” back when scrolling exceeds the bounds of the content.
Source Documentation
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.