Programmatically zooming into small area of larger picture using UIScrollView - iphone

I'm trying to get my code to programmatically zoom into a small area of the larger picture. I'll add the tap code later, but right now I just want to see it work.
The zoomToRect in this code does absolutely nothing and I simply don't understand why. When I build it, the image just sits there at the 0,0 origin.
I've tried using:
setContentOffset and scrollRectToVisible and both these work fine -the image moves to the specified coordinates. But neither of these is what I want, because I need to move and zoom the image, not just move it.
But zoomToRect utterly refuses to do anything. I've read about 50 pages of examples and tutorials on this now and not a damn thing works. I'm tearing my hair out not knowing why. Clearly I'm missing some really fundamental or important point.
UIImage *myFirstImage = [UIImage imageNamed:#"manga_page.jpg"];
UIImageView *myFirstImageView = [[UIImageView alloc] initWithImage:myFirstImage];
[myFirstImageView setFrame:CGRectMake(0, 0, myFirstImage.size.width, myFirstImage.size.height)];
UIScrollView *myFirstScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
[myFirstScrollView setContentSize:CGSizeMake(myFirstImage.size.width, myFirstImage.size.height)];
[myFirstScrollView addSubview:myFirstImageView];
[self.view addSubview:myFirstScrollView];
[myFirstScrollView zoomToRect:CGRectMake(300, 300, 300, 300) animated:YES];

The problem was that I hadn't defined the delegate for zooming - see viewForZoomingInScrollView (bottom of page) here:
https://developer.apple.com/library/ios/documentation/uikit/reference/uiscrollviewdelegate_protocol/Reference/UIScrollViewDelegate.html#//apple_ref/occ/intfm/UIScrollViewDelegate/viewForZoomingInScrollView
I don't have a code fragment in Objective C as I switched to the Xamarin framework. However the C# solution is as follows:
scrollView.ViewForZoomingInScrollView = delegate (UIScrollView sv) { return imageView; };
Where imageView is the UIImageView containing the image to be scrolled around.

Set the maximumZoomScale and minimumZoomScale properties for the UIScrollView.

Related

CATransform3D weird UIScrollView contentOffset

I'm doing a cool CA3DTransform while a UIScrollview is scrolling in the scrollViewDidScroll delegate method. It works perfectly when you use your finger to scroll, so when scrolling manually everything is perfect.
But, when I set scrollview contentoffset programmatically like:
[scrollView setContentOffSet:CGPointMake(0,460) animated:YES];
It still calls the delegate method scrollviewdidscroll, so the same animation methods are called, so I still see the correct animation, BUT, somehow parts of the view are missing during and after the animation! I've tried to set the layer.zPosition on all things and it doesn't seem to help. It should be fine since manually scrolling does work without parts of views going missing... Somehow calling this method programmatically differs and I have no idea why!
Post your question in this way is not very clear, considering that with the delegate scrollViewDidScroll, I can print me the code, either manually or programmatically.
...
UIScrollView *sv = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 10, 320, 200)];
[sv setContentSize:CGSizeMake(640, 200)];
sv.delegate = self;
[sv setContentOffset:CGPointMake(320, 0) animated:YES];
[self.view addSubview:sv];
...
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
NSLog(#"---%#---", NSStringFromCGPoint(scrollView.contentOffset));
}
In this simple example, you can see that the delegate actually works.
Excuse the simplicity of the answer, but the only question you ask is hard to give you help.
I had a similar problem (in the context of using a scrollview for a slideshow) but solved it by using scrollRectToVisible:NO (NO for no animations), and wrapped that inside a UIView animation block where I also put my animation code.

Changing frame of UIView's CALayer (self.view.layer.frame = ...) appears to have no effect

I'm sure I'm missing something basic here. I'm trying out the CALayers 'hello world' code from:
http://www.raywenderlich.com/2502/introduction-to-calayers-tutorial
Doing the very first example. New single view project in xcode 4.2. No change to the nib/storyboard. Import QuartzCore. Add the following code to ViewDidLoad in the ViewController.m:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.layer.backgroundColor = [UIColor blueColor].CGColor;
self.view.layer.cornerRadius = 30.0;
self.view.layer.frame = CGRectMake(20, 20, 20, 20);
}
I run this (ipad 2 or ipad simulator) and get a full screen blue rectangle with rounded corners. What I hoped to get was a 20x20 blue rectangle offset by 20/20.
I'm clearly getting control over the views layer (as shown by the color and rounded corners). However, adjusting the frame seems to have no impact. I've NSLog'ed the frame before/after setting it, and it has changed. Is the frame of the root layer locked to the uiview frame?
I don't have a strong reason to change the views layers frame, I'm just trying to reason through what is going on. Hopefully this is an easy question...
Thanks!
Paul
Actually, the previous answer (you can't set uiview.layer.frame as it always fills the uiview) is close, but not quite complete. After reading the answer, I registered for the original site and to comment that the tutorial had issues. In doing so, I found that there were already comments that I hadn't seen in my first pass that addressed this. Using those, I started doing some testing.
The bottom line, if you move the self.view.layer.frame setting code from viewDidLoad to viewWillAppear, it works fine. That means that you can change the frame of the root layer of a view. However, if you do it in viewDidLoad it will be undone later.
However, the previous answer is still pretty close. I NSLog'ed the frame of the root layer and the frame of the view. Changing the root layer frame changes the view frame. So, the answer that the view.layer.frame always fills the view.frame is correct. However, setting the layer frame resets the view frame to match. (I'm guessing that uiview.frame property simply returns uiview.layer.frame...)
So, at some point in time between 2010 and today, something in the environment changed. Specifically, after viewDidLoad and before viewWillAppear the uiview/layer frame appears to be reset to the nib specified value. This overrides any changes in viewDidLoad. Changes made in viewWillAppear appear to stick.
Robin's answer got me on the right track, but I wanted to spell out the full answer.
The tutorial is wrong. Setting the frame of the view's main layer has no effect. The main layer is 'special' and will always fill the view's bounds. What you need to do is create a sublayer of the main layer like this:
- (void)viewDidLoad
{
[super viewDidLoad];
CALayer *newLayer = [[CALayer alloc] init];
newLayer.backgroundColor = [UIColor orangeColor].CGColor;
newLayer.cornerRadius = 20.0;
newLayer.frame = CGRectMake(100.0f, 100.0f, 200.0f, 200.0f);
[self.view.layer addSublayer:newLayer];
[newLayer release]; // Assuming you're not using ARC
}
Also, in your code a layer with width 20pt and height 20pt is too small to have rounded corners of 30pt anyway.

How do I use CGRectMake to size the background

Ok So I have this code, which allows me to put a background image in:
I would love to know how to size this, so on the iPhone 4 I can get a 320x480 size but make it nice with an image of 570.855.
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background_stream-570x855.jpg"]];
I have tried this:
UIImageView *image = [[UIImageView alloc]
initWithImage:[UIImage imageNamed:#"background_stream-570x855.jpg"]];
[self.view sendSubviewToBack:streamBG];
image.frame = CGRectMake(0, 0, 320, 480);
Which works, however the problem is it's behind the view, so I can't see it. I could make the view clear, but it has objects on it that need to be displayed.
Any help would be most apretiated
There are multiple options to put Views at desired location.
[self.view sendSubviewToBack:streamBG]; //Sends subview to last position i.e. at the last
[self.view bringSubviewToFront:streamBG] //Brings subview to first position i.e. at the first.
[self.view insertSubview:streamBG atIndex:yourDesiredIndex];//Put at desired index.
This is not answer to your question, though it may help you to set your imageview to desired location.
Hope it helps.
To answer part of your question about sizing. You need to use 2 different images for your app if you want the full resolution of the retina display (iPhone4) You should provide a 320x480 image (i.e. myImage.png) for older iPhones and one at twice the resolution, 640x960, for the iPhone 4. Use the exact same name for the high res version but add an "#2x" to the end (i.e. myImage#2x.png). In your code all you ever have to call is the base name (i.e. myImage.png) the app will choose the correct image based on the hardware its running on. That will get you the best experience on your app.
On the other part about the background view visibility, you could make the background color clear ([UIColor clearColor]) on the view that is blocking it. That would leave the content visible in that view but the view its self would be clear. Alternatively you could just insert the background at a specific index as #Jennis has suggested instead of forcing it to the back.

UIScrollView scrollRectToVisible isn't doing anything

I'm not really sure why this isn't working, hopefully you can help me find the missing piece. I have a UIScrollView with paging enabled. I'm using it for side-scrolling through a tutorial. I have a button that when tapped should scroll the user back to the beginning of the tutorial. I originally tried using the scroll view's frame as the rect to scroll to because that CGRect should represent the first page. I've tried a couple of different CGRects to no avail though.
- (IBAction) touchedButtonReturnToBeginning:(id)sender {
// I've tried several CGRect's, none of which cause the UIScrollView to move.
// CGRect beginning = self.containerScrollView.frame
// CGRect beginning = self.containerScrollView.bounds;
CGRect beginning = CGRectMake(0, 44, 1, 1);
[self.containerScrollView scrollRectToVisible:beginning animated:YES];
}
I have verified that self.containerScrollView is hooked up in my xib as well as the touchedButtonReturnToBeginning action is connected to my button. I've used my debugger to step through this method, so I have verified that it is getting called. All of the variables are appropriately set, but when I call scrollRectToVisible the scroll view just doesn't do anything.
Any ideas?
I don't know why that wouldn't work, but have you tried [self.containerScrollView setContentOffset:CGPointZero animated:YES]?
To make scrollRectToVisible works check your self.containerScrollView.contentSize. It should be big enough :)

How to determine image coordinates for a large cropped image within a UIImageView?

With regards to the iPhone SDK:
I have a 512 x 512 pixel .png image, and I want to display it within a 200 x 200 pixel UIImageView WITH cropping (at native resolution, without zooming, fitting, or rotation). Is there a way to determine the image's coordinates that are visible inside the UIImageView?
For example, if the image in the exact center of the UIImageView, then I want to know what the coordinates of the image are at UIImageView's (0,0) and (200,200) points, which will be (156,156) and (356,356), respectively for the image being displayed.
I plan on implementing "pan" and "zoom" functions at some point, but I want to know how to address this issue first. The UIImageView class reference did not seem helpful... I was hoping to avoid using a UIView, but if that is necessary I will go that route.
Thanks!
You're right about what you've seen from the UIImageView reference - there is no easy way to do that using UIImageView alone. You would need to take into account things like the contentMode of the UIImageView or limit yourself to only calculating the position for a single UIViewContentMode.
However, when you eventually get to implementing pan and zoom, you'll be using a UIScrollView with a UIImageView as a subview of that UIScrollView. At that point, it would be most sane to size your UIImageView initially to the size of whatever image you're display (could be dynamic). You can then determine where the image is by determining where the image view is, which is something you can accomplish much more simply and with just a bit of math.
Thanks for your help. Working out the pan/zoom features became trivial after implementing the UIScrollView. Implementing the UIScrollView let me determine the coordinates I needed with the myScrollView.bounds.origin.x and myScrollView.bounds.origin.y values... zooming still requires calculation - as you stated above, but I am on the right track now.
here is the code I used to make the UIScrollView (based on multiple sources available on the net and this site - Apple's ScrollViewSuite was particularly helpful. Here is the code I used in the (void)viewDidLoad section of my program, hopefully others can find it useful:
UIImageView *tempImageView = [[UIImageView alloc] initWithImage:[imageArray objectAtIndex:0]]; //imageArray is an array/stack of images...
[self setMyImage:tempImageView]; //myImage is of type UIImageView
[myImage setTag:100]; //set this to an 'arbitrary' value so that when I update the scrollview I can remove the current image...
[tempImageView release];
myScrollView.contentSize = CGSizeMake(myImage.frame.size.width, myImage.frame.size.height);
myScrollView.maximumZoomScale = 10.0;
myScrollView.minimumZoomScale = 0.15;
myScrollView.clipsToBounds = YES;
myScrollView.delegate = self;
[myScrollView addSubview:myImage];