Search This Blog

Monday, September 13, 2010

UIScrollView

UIScrollView Image Gallery Tutorial

Using a UIScrollView to create a paging application seems to be a question I am frequently asked about. I decided to create this tutorial to show how you can create an image gallery with a UIScrollView. I will show you have to reuse two UIImageViews views to avoid creating a UIImageView for each image in the gallery. Full tutorial and source after the jump.

I will highlight the most important bits of code here. The rest can be downloaded at the end of this post.

In the init method we will create our UIScrollView and two UIImageViews. The UIScrollView will be added to the UIViewControllers view. Each of the UIImageViews will be added as a child of the UIScrollView. We make sure that paging is enabled to give it that default iPhone paging effect. We also want the directionalLockEnabled to prevent dragging in other directions once dragging has begun. The scroll indicators are hidden but this is not a requirement. Our UIViewController is then set as the delegate for the UIScrollView so we know when scrolling has occurred.

01- (id) init
02{
03 if(self = [super init])
04 {
05 scroll = [[UIScrollView alloc] init];
06 scroll.scrollEnabled = YES;
07 scroll.pagingEnabled = YES;
08 scroll.directionalLockEnabled = YES;
09 scroll.showsVerticalScrollIndicator = NO;
10 scroll.showsHorizontalScrollIndicator = NO;
11 scroll.delegate = self;
12 scroll.backgroundColor = [UIColor blueColor];
13 scroll.autoresizesSubviews = YES;
14 scroll.frame = CGRectMake(0, 0, 320, 480);
15 [self.view addSubview:scroll];
16
17 view1 = [[UIImageView alloc] init];
18 [scroll addSubview:view1];
19
20 view2 = [[UIImageView alloc] init];
21 [scroll addSubview:view2];
22 }
23
24 return self;
25}

In our UIViewController we are going to implement the scrollViewDidScroll method. I created an update method that is called from here. This is just a personal preference based on my own organizational habits. I will go over the update method last.

1- (void) scrollViewDidScroll:(UIScrollView *) scrollView
2{
3 [self update];
4}

Next up is out setImages method. This method is public and will be called from the UIViewControllers parent in order to load our images. With this methods we can pass in an NSArray of UIImage objects. If a set of images has already been added we will release the current set and store the new set. In this method we will also set the initial location of our UIImageViews by altering their frame. We will also load the first images from our new set of images into our UIImageViews. Last in this method we will set the contentSize property of the UIScrollView. This will tell our UIScrollView how much content to expect. (Note: I am using hard coded values of 320x480 as the screen size. This can be altered to grab the actual size of the screen if needed.)

01- (void) setImages:(NSArray *) images
02{
03 if(imageSet) [imageSet release];
04
05 imageSet = [images retain];
06
07 view1.frame = CGRectMake(0, 0, 320, 480);
08 view2.frame = CGRectMake(320, 0, 320, 480);
09
10 view1.image = [imageSet objectAtIndex:0];
11 view2.image = [imageSet objectAtIndex:1];
12
13 scroll.contentSize = CGSizeMake([imageSet count]*320, 480);
14}

The last step in this is to update the positions of our UIImageViews and reload the images as it scrolls. In this method we take the screen width and the current position of the UIScrollView to calculate which index in our images array is currently visible. We use the modulo operation to figure out which UIImageView we should use. If the index is 0 we should use view1, if the index is 1 we should use view 2, if the index is 2 we should use view1 etc. We also calculate the true position. By this I mean the x value of the currently visible UIImageView. We can now figure out which index is next based on the truePosition and the position the UIScrollView is currently at. We also need to make sure that our next index isn’t out of range and is within the bounds of our images array. We also want to make sure we aren’t reloading and repositioning an image that has already been set. Once everything is calculated we can then update the UIImageView with the new image based on the next index and set the position based on that index as well.

01- (void) update
02{
03 CGFloat pageWidth = 320;
04 float currPos = scroll.contentOffset.x;
05
06 int selectedPage = roundf(currPos / pageWidth);
07
08 float truePosition = selectedPage*pageWidth;
09
10 int zone = selectedPage % 2;
11
12 BOOL view1Active = zone == 0;
13
14 UIImageView *nextView = view1Active ? view2 : view1;
15
16 int nextpage = truePosition > currPos ? selectedPage-1 : selectedPage+1;
17
18 if(nextpage >= 0 && nextpage < [imageSet count])
19 {
20 if((view1Active && nextpage == view1Index) || (!view1Active && nextpage == view2Index)) return;
21
22 nextView.frame = CGRectMake(nextpage*320, 0, 320, 480);
23 nextView.image = [imageSet objectAtIndex:nextpage];
24
25 if(view1Active) view1Index = nextpage;
26 else view2Index = nextpage;
27 }
28}
That’s the end, I hope everything makes sense. This was my first tutorial so I hope it turned out well. Please let me know if there are any question via the comments.

No comments:

Post a Comment