Thursday, October 23, 2008

Scroll Views

I've been realizing over the last couple of days that we missed covering something in the book that we should have: UIScrollView. Now that I've spent a few days fighting them, I must admit that I'm glad I missed it. These things are complex and not as well documented as they should be. I've got my app working with hit testing inside of a scroll view, and without jaggies, but my performance isn't good. Here's the thing:

UIScrollView ALWAYS starts at a zoom of 1.0. You can't change this. If you do, it will just cause it to act funny the first time the user touches the screen (please, if I'm wrong on this, correct me). But, if you zoom in on a view, it gets all pixelated and blocky unless you change your content view's (and/or subview's) backing layer to a CATiledLayer. Doing that kills performance on my first generation iPhone. I haven't tested it yet on my second generation iPod Touch, but I suspect it will only be a little bit better.

But, here's the thing. If I change the size so that I start zoomed in... so that the content view is the size of the zoomed view and don't use CATiledLayer, it works beautifully, scrolls fast, no skips, etc. But, I don't want the user to have to start zoomed way in. The program won't be intuitive if I do that.

A related problem is that I can't get the double-tap zoom and unzoom working. In an old edition of the iPhone Programming guide, there was sample code that supposedly showed how to do that, but I've tried it, and many, many variants of it, and never have gotten it to work right. There might be a reason why that code sample is no longer in the programming guide.

Anybody out there gotten this working?



11 comments:

William Dahlberg said...

I've been fighting with these things for a while now, they are evil. I have a paged scroll view that contains a bunch of other scroll views that are used to zoom and pan in images with, kind of like the built in photo app. The images have a resolution greater than the iPod screen so I use scroll views to be able to zoom in to a 1:1 scale and pan around. I haven't had to use CATiledLayer but the way I made it to be initially zoomed out was to first load the image into an UIImageView. This automatically sets the frame of the UIImageView to the size of the image. Then I resize the UIImageView's frame to the size of the screen which will scale the image so it fits the screen. Then I set the content size and max zoom scale like so (keeping the minimum zoom scale at the default 1.0):
scrollView.contentSize = imageView.image.size;
scrollView.maximumZoomScale = imageView.image.size.width/imageView.frame.size.width;

To zoom in/out on double tap I added these two methods in my UIScrollView subclass:
- (void)zoomOut
{
if (zoomed)
{
UIImageView* imageView = [self.subviews objectAtIndex:0];

[UIView beginAnimations:nil context:nil];
imageView.frame = CGRectMake(0, 0, 320, 480);
self.contentOffset = CGPointMake(0, 0);
self.minimumZoomScale = 1;
self.maximumZoomScale = imageView.image.size.width/imageView.frame.size.width;
[UIView commitAnimations];

zoomed = NO;
}
}

- (void)zoomInTo:(CGPoint)location
{
if (!zoomed)
{
UIImageView* imageView = [self.subviews objectAtIndex:0];

[UIView beginAnimations:nil context:nil];
imageView.frame = CGRectMake(0, 0, imageView.image.size.width, imageView.image.size.height);
self.contentSize = imageView.image.size;
self.minimumZoomScale = 320.0f/imageView.image.size.width;

self.contentOffset = location;
self.maximumZoomScale = 1;
[UIView commitAnimations];

zoomed = YES;
}
}

I'm working on this right now so it's not so polished, should probably fetch the screen size programmatically, but hey it works.

Thanks for a great blog with some really helpful tips by the way!
/ www.williamdahlberg.com

Hal Mueller said...

The pixellated blocky look is fixed by setting levelsOfDetail and levelsOfDetailBias on the UIScrollView's content view's layer.

From my content view class's initWithFrame:

CATiledLayer *animLayer = (CATiledLayer *) self.layer;
animLayer.levelsOfDetailBias = 4;
animLayer.levelsOfDetail = 4;

Jeff LaMarche said...

William:

Thanks, that's a huge help. I'll try it out.

Hal:

Thanks to you too - I got that info from your tutorial, but I took quite a performance hit from the CATiledLayer. Doing it for the content view wasn't enough, I had to do it for every subview also, and scrolling got really choppy. :(

watmough said...

I got this working by recreating the scroll and content views after any change in scale.

This gets rid of jaggies, and allows tap zooming and pinch to coexist peacefully.

See codez on my blog at jonathanwatmough.com

demetrius said...

I have a really good example of tap/zoom.

Demetrius

Maneesh Rampally said...

Hi Demetrius can you post your tap/zoom example which you have.

Buzz said...

This thread appears to not address one issue that has been very painful for me... how is the "tap" (touch) on the image captured? I have a large image that I can scroll, zoom and pan, but can't get my app to recognize the touchesBegan event. Any suggestions/guidance would be very appreciated, thanks!

Edwin said...

scrub m65 kamagra attorney lawyer body scrub field jacket lovegra marijuana attorney injury lawyer

antywong said...

The rounded shape of speedy 30 features textile fake louis vuitton lining and leather trimmings with shiny Louis Vuitton Monogram ldylle Romance Encre golden brass. Sized at 11.8" x 8.3" x 6.7", the large capacity Hermes Original Python Birkin 30 Grey of this bag is enough for handbags review daily essentials; you can put bags wholesale everything into this city bag. It also fits for Hermes Clemence Jypsiere 34 Purple every occasion and perfectly goes with any outfits mfakng100910.

h4ns said...

What youre saying is completely true. I know that everybody must say the same thing, but I just think that you put it in a way that everyone can understand. I also love the images you put in here. They fit so well with what youre trying to say. Im sure youll reach so many people with what youve got to say.

Arsenal vs Huddersfield Town live streaming
Arsenal vs Huddersfield Town live streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Notts County vs Manchester City Live Streaming
Notts County vs Manchester City Live Streaming
Bologna vs AS Roma Live Streaming
Bologna vs AS Roma Live Streaming
Juventus vs Udinese Live Streaming
Juventus vs Udinese Live Streaming
Napoli vs Sampdoria Live Streaming
Napoli vs Sampdoria Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
AS Monaco vs Marseille Live Streaming
AS Monaco vs Marseille Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Technology News | News Today | Live Streaming TV Channels

louis vuitton spring summer 2010 collection said...

Discover Louis Vuitton collections online: luggage, handbags, wallets, shoes ...