May 2, 2013

UIScrollView With Page Numbers (UIPageControl-like)


Overview

When using UIScrollView in paging mode, it is quite common to incorporate it with UIPageControl for simpler navigation. This tutorial shows how to create completely custom page control with page numbers which works very similar to UIPageControl

Here's how final result looks like:

1. Setting up the project 

Open XCode and create new project using Single View Application template: 


Name the project, select "iPhone" option from "Devices" menu, make sure that "Use Automatic Reference Counting" is checked, press "Next" one more time and save your project.

2. Adding graphics

In order to create custom page control, you will need two pictures which would be used for disabled/enabled page background similar to these:


(note that @2x version of the files should be added for Retina display support)


3. Adding functionality 

Setting up ViewController.h

We will need to create scroll view and an array to store page control elements. Also we will need to access UIScrollView's delegate method, so here's how file should look like:


#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UIScrollViewDelegate>
{
    UIScrollView* scrollView;

    NSMutableArray *PageControlBtns;
}
@end



Setting up ViewController.m

First, let's define pages number at the top of the file:


#define PAGES_NUMBER 6


Next, let's modify viewDidLoad function by adding scroll view and calling GeneratePages function which is going to generate page control:


- (void)viewDidLoad
{
    [super viewDidLoad];
    
    scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(50.0, 50.0, self.view.frame.size.width-100.0, self.view.frame.size.width-100.0)];
    scrollView.pagingEnabled = YES;
    scrollView.showsHorizontalScrollIndicator = NO;
    scrollView.delegate = self;
    scrollView.backgroundColor = [UIColor clearColor];
    [self.view addSubview:scrollView];
    
    [self GeneratePages];
}


Now we are going to actually generate pages in loop, which includes following:

  • Creating UIView (Page) with label which displays current page number, and adding this page to scroll view
  • Creating UIButton with page number label which represents page control element, adding this button to view, and storing it in the array. Each button has appropriate tag, so that when onPageControlBtnPressed: is called, we will know exactly which button was pressed.
Here's function implementation:

-(void)GeneratePages
{
    UIImage *PageControlImg = [UIImage imageNamed:@"page_deselected.png"];
    int x_coord = (self.view.frame.size.width-PageControlImg.size.width*PAGES_NUMBER)/2.0;
    
    PageControlBtns = [[NSMutableArray alloc] init];
    
    for (int i=0; i<PAGES_NUMBER; i++)
    {
        
        UIView *Page = [[UIView alloc] initWithFrame:CGRectMake(scrollView.frame.size.width*i, 0.0, scrollView.frame.size.width, scrollView.frame.size.height)];
        Page.backgroundColor = [UIColor colorWithRed:0.32 green:0.55 blue:0.88 alpha:1.0];
        
        UILabel *titleLbl = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 10.0, Page.frame.size.width-20.0, 40.0)];
        titleLbl.backgroundColor = [UIColor clearColor];
        titleLbl.textColor = [UIColor whiteColor];
        titleLbl.font = [UIFont boldSystemFontOfSize:16.0];
        titleLbl.text = [NSString stringWithFormat:@"This is page number %d", i+1];
        titleLbl.textAlignment = UITextAlignmentCenter;
        [Page addSubview:titleLbl];
        
        [scrollView addSubview:Page];
        
        UIButton *PageControlBtn = [[UIButton alloc] initWithFrame:CGRectMake(x_coord+i*PageControlImg.size.width, scrollView.frame.origin.y+scrollView.frame.size.height+20.0, PageControlImg.size.width, PageControlImg.size.height)];
        [PageControlBtn setBackgroundImage:[UIImage imageNamed: (i==0)?@"page_selected.png":@"page_deselected.png"] forState:UIControlStateNormal];
        [PageControlBtn setBackgroundImage:[UIImage imageNamed: @"page_selected.png"] forState:UIControlStateHighlighted];
        [PageControlBtn setBackgroundImage:[UIImage imageNamed: @"page_deselected.png"] forState:UIControlStateDisabled];
        [PageControlBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
        [PageControlBtn setTitleColor:(i==0)?[UIColor whiteColor]:[UIColor grayColor] forState:UIControlStateNormal];
        PageControlBtn.titleLabel.font = [UIFont boldSystemFontOfSize:16.0];
        PageControlBtn.titleLabel.textAlignment = UITextAlignmentCenter;
        [PageControlBtn setTitle:[NSString stringWithFormat:@"%d", i+1] forState:UIControlStateNormal];
        [PageControlBtn setTitle:[NSString stringWithFormat:@"%d", i+1] forState:UIControlStateSelected];
        [PageControlBtn setTag:i+2000];
        [PageControlBtn addTarget:self action:@selector(onPageControlBtnPressed:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:PageControlBtn];
        
        [PageControlBtns addObject:PageControlBtn];
    }
    scrollView.contentSize = CGSizeMake(scrollView.frame.size.width*PAGES_NUMBER, scrollView.frame.size.height);
}

Now, when any button is pressed, we need to do two things - manually scroll UIScrollView to appropriate page and change button look (both background image and text color), which is going to be implemented in a separate function:


-(void)onPageControlBtnPressed:(id)sender
{
    UIButton *button = (UIButton *)sender;
    
    int tag=button.tag-2000;
    
    [scrollView setContentOffset:CGPointMake(scrollView.frame.size.width*tag, 0) animated:YES];
    
    [self SetActivePageControlWithIndex:tag];
}

-(void)SetActivePageControlWithIndex:(int)index
{
    for (int i=0; i<[PageControlBtns count]; i++)
    {
        UIImage *backgroundImg = [[PageControlBtns objectAtIndex:i] backgroundImageForState:(i==index)?UIControlStateHighlighted:UIControlStateDisabled];
        [[PageControlBtns objectAtIndex:i] setBackgroundImage:backgroundImg forState:UIControlStateNormal];
        [[PageControlBtns objectAtIndex:i] setTitleColor:(i==index)?[UIColor whiteColor]:[UIColor grayColor] forState:UIControlStateNormal];
    }
}


By now pressing a button would change scroll view's position, but it doesn't work vise-versa. So, we should change active page control when scroll view is scrolled. To do this, we will use UIScrollView's delegate method:

-(void)scrollViewDidEndDecelerating:(UIScrollView *)sender
{
    CGFloat pageWidth = scrollView.frame.size.width;
    int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
    [self SetActivePageControlWithIndex:page];
}

That's it - now you get response both ways - when scroll view is scrolled and when page control button is pressed. You can download source codes here.

2 comments:

  1. Mobile app gives a look to business app. A perfectly designed website always attracts more visitors. Even the simple factors like font color, font size plays a great role in making a mobile app attractive. We provide experienced team of website designers that lay emphasis on such minute details while designing.

    Cado Magenge
    " mobile apps development companies melbourne
    web design and development company
    app development company
    iphone application development melbourne "

    ReplyDelete
  2. in pagecontrol when we moved to next one the content in the first one only reading how to make changes like this scenario in accessbility, in swift.

    ReplyDelete