Design & Build a Small Business App: AQGridView

Design & Build a Small Business App: AQGridView

Tutorial Details
  • Technology: iOS SDK
  • Difficulty: Intermediate
  • Completion Time: 30 - 60 Minutes
This entry is part 2 of 3 in the series Design & Build a Small Business App

Welcome to the second of three installments in our series on building a small business app from scratch. This tutorial will teach you how to implement an AQGridView within your project in order to achieve a stunning design. Read on!


Tutorial Overview

In this tutorial, I will go about designing the screen you see in the image below. The screen you see below has a grid of tabs that can be used to show a company’s services. We are going to use an Open Source component called AQGridView to implement the Grid you see below.

AQGrid views behave similarly to the UITableViewController, so if you are familiar with using Table Views, you are in good company. If not, I will show you how. No worries!


Adding the Grid Cell

So, the first step is to download AQGrid view from GitHub and then add the AQGridView folder to your project. We also need to add the QuartzCore library to our project because the AQGrid view needs it. We don’t need anything else for now.

Now we can add the class that will hold the details for each tab. Add a new file to the project. Choose the Cocoa Touch->Objective -C Class->NSObject template. Call it GridViewCell.

Change the inherited object to AQGridViewCell in the GridViewCell header file. This is the equivalent of a UITableViewCell for the Grid view component. Also, add an Image View and a Label to the the same header file.

#import <UIKit/UIKit.h>
#import "AQGridView.h"
@interface GridViewCell : AQGridViewCell
@property (nonatomic, retain) UIImageView * imageView;
@property (nonatomic, retain) UILabel * captionLabel;
@end

In the GridViewCell.m implementation file, we will write an initialization method that will create the Views, Image Views, and Label that will make up a single tab.

- (id) initWithFrame: (CGRect) frame reuseIdentifier: (NSString *) aReuseIdentifier
{
    self = [super initWithFrame: frame reuseIdentifier: aReuseIdentifier];
    if ( self)
    {
        UIView* mainView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 160, 123)];
        [mainView setBackgroundColor:[UIColor clearColor]];
        UIImageView *frameImageView = [[UIImageView alloc] initWithFrame:CGRectMake(9, 4, 142, 117)];
        [frameImageView setImage:[UIImage imageNamed:@"tab-mask.png"]];
        self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(13, 8, 135, 84)];
        self.captionLabel = [[UILabel alloc] initWithFrame:CGRectMake(13, 92, 127, 21)];
        [captionLabel setFont:[UIFont systemFontOfSize:14]];
        [mainView addSubview:imageView];
        [mainView addSubview:frameImageView];
        [mainView addSubview:captionLabel];
        [self.contentView addSubview:mainView];
    }
    return self;
}

This function looks similar to the init function of a standard UITableViewCell. The difference in this case is we are doing some basic layout for the views involved in the cell. There are two ImageViews, one for the white frame around the service image and another for the picture depicting the service itself. Please refer to the final image to understand what we are trying to achieve.

There is also a label which will be used as the caption of the tab.

After the views have been created, they are added to a UIView (just for organization) and then that UIView is added to the cell itself.


Creating the Grid Controller

The next step is to create the View controller that will act as the delegate and datasource of the Grid. Add a new file and use the Cocoa Touch->Objective -C Class->NSObject template. Call it GridViewController. Change the GridViewController.h file and make it a subclass of AQGidViewController. Also add a couple of fields that will hold the GridView itself and the list of services that will be in the Grid.

#import <UIKit/UIKit.h>
#import "AQGridView.h"
@interface GridViewController : UIViewController <AQGridViewDelegate, AQGridViewDataSource>
@property (nonatomic, retain) IBOutlet AQGridView * gridView;
@property (nonatomic, retain) NSArray * services;
@end

Add a viewDidLoad method. This is where we shall configure our Views and data. But first, let’s configure the GridView.

@synthesize gridView, services;
- (void) viewDidLoad
{
    [super viewDidLoad];
    self.gridView = [[AQGridView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
    self.gridView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
	self.gridView.autoresizesSubviews = YES;
	self.gridView.delegate = self;
	self.gridView.dataSource = self;
    [self.view addSubview:gridView];
    [self.gridView reloadData];
}

The mandatory synthesizer is added then the Grid is initialized and configured. We also make sure that the current class GridViewController is assigned as the delegate and datasource of the GridView. The Grid is added to the current view and the data is reloaded just to make sure we are starting from scratch.

Now we need to implements the methods that are expected to be in a class that inherits from AQGridViewDatasource and AQGridViewDelegate protocols.

The first one is the number of items in the Grid. We simply return a random number for now. Later, when we implement an array of services, this number will change.

- (NSUInteger) numberOfItemsInGridView: (AQGridView *) aGridView
{
    return 6;
}

The next method to implement is called cellForItemAtIndex. This method dequeues a cell using the CellIdentifier string if it can find one. If it doesn’t, it will create a new version of our GridViewCell that we previously implemented.

- (AQGridViewCell *) gridView: (AQGridView *) aGridView cellForItemAtIndex: (NSUInteger) index
{
    static NSString * PlainCellIdentifier = @"PlainCellIdentifier";
    GridViewCell * cell = (GridViewCell *)[aGridView dequeueReusableCellWithIdentifier:@"PlainCellIdentifier"];
    if ( cell == nil )
    {
        cell = [[GridViewCell alloc] initWithFrame: CGRectMake(0.0, 0.0, 160, 123)
                                   reuseIdentifier: PlainCellIdentifier];
    }
    [cell.imageView setImage:[UIImage imageNamed:@"service-2.jpg"]];
    [cell.captionLabel setText:@"Sample service"];
    return cell;
}

You can also see that each cell is configured with some dummy data.

So far, we have been implementing a lot of code without seeing the result of the implementation. Let’s do a quick run to see how things turn out.

To be able to see this view in the simulator, we will need to let our Storyboard know about this new ViewController.

Select the MainStoryboard_iPhone file and change the Class of the SecondViewController nib to GridViewController. Also delete both labels in the View.

Now we are ready to run our little app in the simulator. We should see the following screen.

Disappointed? Doesn’t look like what you expected, right? Okay let’s fix that.


Implementing the Grid Layout

The first step is to change the background color. For that, we are going to use a fabric texture which is included in the sample project.

Open up the GridViewController.m file and add these two lines to the viewDidLoad method:

    UIImage * backgroundPattern = [UIImage imageNamed:@"bg-app.png"];
    [self.view setBackgroundColor:[UIColor colorWithPatternImage:backgroundPattern]];

Next, we need to implement the AQGridViewDataSource protocol method:

- (CGSize) portraitGridCellSizeForGridView: (AQGridView *) aGridView
{
    return ( CGSizeMake(160.0, 123) );
}

This method tells the Grid view how large each cell should be. The size is taken from the size of the GridViewCell we created previously.

If you now run the application in the simulator, you should see the screen below:

Now that’s more like it!


Implementing a Data Model

Our cells could do with a bit more diversity. Let’s add a data model to it so the services can come from some sample data. This will ideally be the list of services of the business that owns the app. You could connect to a website CMS and pull its categories as well. However, that is out of the scope of this tutorial series.

Add a new Cocoa Touch->NSObject file to the application and call it BusinessService. Open up the BusinessService.h file and add the following code:

#import <Foundation/Foundation.h>
@interface BusinessService : NSObject
@property (nonatomic, copy) NSString* caption;
@property (nonatomic, retain) UIImage* image;
-(id)initWithCaption:(NSString*)theCaption andImage:(UIImage*)theImage;
+(NSArray*)getSampleData;
@end

This is going to be a very simple class with just a caption and an image. It is also defined by two methods that I will explain shortly.

Open up the BusinessService.m file and add the following piece of code

@synthesize caption, image;
-(id)initWithCaption:(NSString*)theCaption andImage:(UIImage*)theImage
{
    self = [super init];
    if(self)
    {
        self.caption = theCaption;
        self.image = theImage;
    }
    return self;
}
+(NSArray*)getSampleData
{
    BusinessService* service1 = [[BusinessService alloc] initWithCaption:@"Litigation" andImage:[UIImage imageNamed:@"service-1.jpg"]];
    BusinessService* service2 = [[BusinessService alloc] initWithCaption:@"Family Law" andImage:[UIImage imageNamed:@"service-2.jpg"]];
    BusinessService* service3 = [[BusinessService alloc] initWithCaption:@"Conveyancing" andImage:[UIImage imageNamed:@"service-3.jpg"]];
    BusinessService* service4 = [[BusinessService alloc] initWithCaption:@"Corporate Law" andImage:[UIImage imageNamed:@"service-4.jpg"]];
    BusinessService* service5 = [[BusinessService alloc] initWithCaption:@"Solicitors" andImage:[UIImage imageNamed:@"service-5.jpg"]];
    BusinessService* service6 = [[BusinessService alloc] initWithCaption:@"Tax Law" andImage:[UIImage imageNamed:@"service-6.jpg"]];
    return [NSArray arrayWithObjects:service1, service2, service3, service4, service5, service6, nil];
}

The code above implements an init method where both the caption and the image are initialized using the parameters passed into the function. The getSampleData method just calls the init function 6 times with different captions and images.

We now need to hook up our model to the Grid View. Open up the GridViewController.m file and add this to the viewDidLoad method (don’t forget to include the “BusinessService.h” file in the #import section).

    self.services = [BusinessService getSampleData];

This will load the sample data into our array of services.

Also modify the numberOfItemsInGridView to return the actual number of services there are:

- (NSUInteger) numberOfItemsInGridView: (AQGridView *) aGridView
{
    return [services count];
}

And lastly, change the cellForItemAtIndex method to use the service at the specified index. This means the 6th cell will use the info (caption and image) for the 6th service.

- (AQGridViewCell *) gridView: (AQGridView *) aGridView cellForItemAtIndex: (NSUInteger) index
{
    static NSString * PlainCellIdentifier = @"PlainCellIdentifier";
    GridViewCell * cell = (GridViewCell *)[aGridView dequeueReusableCellWithIdentifier:@"PlainCellIdentifier"];
    if ( cell == nil )
    {
        cell = [[GridViewCell alloc] initWithFrame: CGRectMake(0.0, 0.0, 160, 123)
                                   reuseIdentifier: PlainCellIdentifier];
    }
    BusinessService* service = [services objectAtIndex:index];
    [cell.imageView setImage:service.image];
    [cell.captionLabel setText:service.caption];
    return cell;
}

Let’s run the application to see what we get.

That is looking snazzy :-). The last bit left is to add the blue Navigation Bar at the top.


Customizing the Navigation Bar

To show the Navigation Bar, we need to embed it in a Navigation controller. Open the MainStoryboard_iPhone file and select the GridViewController on the stage. Open the Editor Menu Option and Select Embed In>Navigation Controller.

If we run the app, we will get the basic default Navigation bar. We still need to customize it. To do so, we shall use the iOS 5 Appearance SDK. This allows you to set the global appearance of UI Elements in your app.

Open up the AppDelegate.m file and change the didFinishLaunchingWithOptions to the following.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UIImage *navBarImage = [UIImage imageNamed:@"menubar.png"];
    [[UINavigationBar appearance] setBackgroundImage:navBarImage
                                       forBarMetrics:UIBarMetricsDefault];
    // Override point for customization after application launch.
    return YES;
}

What this does is to change the background image of all UINavigationBar’s in the application to the specified UIImage (menubar.png).

To add the “Services” title in the Navigation Bar, double click it in the Storyboard to edit it.

The last step is to add a gradient at the top of the Grid so that the Navigation Bar looks like it is hovering.

To do that, we will add a Gradient CALayer to the GridViewController.m file.

Include the QuartzCore header file:

#import <QuartzCore/QuartzCore.h>

And add this to the bottom of the viewDidLoad method:

    UIView* gradientView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 4)];
    CAGradientLayer *gradient = [CAGradientLayer layer];
    gradient.frame = gradientView.bounds;
    UIColor* lightColor = [[UIColor blackColor] colorWithAlphaComponent:0.0];
    UIColor* darkColor = [[UIColor blackColor] colorWithAlphaComponent:0.5];
    gradient.colors = [NSArray arrayWithObjects:(id)darkColor.CGColor, (id)lightColor.CGColor, nil];
    [gradientView.layer insertSublayer:gradient atIndex:0];
    [self.view addSubview:gradientView];

Now for a final run of our application.


Wrap Up

We have come to the end of Part 2. Look out for Part 3 where I will show you how to design the detail view for each service. When a service tab is tapped on, it will push a new ViewController to the screen and we will start the process of designing that also. Be sure to check back soon!

If you have any questions, please let me know in the comments.

Series Navigation«Design & Build a Small Business App: Project SetupDesign & Build a Small Business App: Custom Detail Views»

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • jessy

    Hi, I have a question. I am implementing an grid view in my app. I have couple of images loading from the documents directory. I am having trouble with the loading the grid view cells when launching the app. The images are loading little late into the cells. How can I avoid it.

    • http://www.appdesignvault.com Tope
      Author

      The images should not load late into the cells, since it is coming from the device and not the web.

      Where are you setting the images i the ImageView?…

  • http://www.thompsonchecksolutions.com Thompson Tickets

    mobile business is on the way nowadays… this is great!..

    • http://www.appdesignvault.com Tope
      Author

      Yes, right on point!

  • stephen

    thanks for the tutorial.it was really helpful.i have a question.in AQGridView Cell.i want to navigate to the next view whent the cell is clicked.is there any delegation or method available?

    • http://www.appdesignvault.com Tope
      Author

      Yes, see Part 3 of this tutorial series to see how it is done

      But for a quick answer, you can use this method in AQGridView

      -(void)gridView:(AQGridView *)gridView didSelectItemAtIndex:(NSUInteger)index

  • Martin

    Thanks!!!

    • http://www.appdesignvault.com Tope
      Author

      You are welcome!

  • http://www.google.com JHollanti

    Seriously cool. Hands down the best tutorial i’ve ever seen about… Well about anything :)

    Thanks, you made my life a whole lot easier.

    • http://www.appdesignvault.com Tope
      Author

      Good to hear you like it! Thanks

  • http://www.searchsourcedesigns.com/ Website Design Las Vegas

    Hey this was really a great collection. Thanks for the tutorial. It was really helpful.

  • gd

    Great Tutorials! thanks.

    Seriously….

    • http://www.appdesignvault.com Tope
      Author

      Thanks, happy you liked it.

  • http://brianramirezcreative.com Brian

    Awesome tutorial so far! Just finished section 1.

    At the beginning of this section however, there is something I feel needs to be addressed. With the introduction of iOS 5.1 Apple discontinued support the used of the reuseIdentifier function. The first part of creating the GridView needs this, what would be a suitable way for support for iOS 5.1?

    • http://www.appdesignvault.com Tope
      Author

      Hi Brian,

      The reuseIdentifier used in the sample above is internal to AQGridView. It has nothing to do with the UITableViewCell reuse identifier….

      So you should be covered :-)

  • http://Me.com Sergei

    When I compile your source code only first 3 images are shown on cells. Services part from tutorial 3 showing all images. Hovewer AQgridView only shows 3 of them. The rest of cells is empty frames, clickable. All images are same size and dpi. Nothing I can see in the code. Is there some memory allocation limit or something broken in the latest Xcode?

  • yui

    Thank for you share code is cool

  • Jon Brown

    I am not sure if I am missing something here but this piece of code is not working for me.

    [mainView setBackgroundColor:[UIColor clearColor]];

    the background is showing up as pure white against the linen background.

    I tested

    [mainView setBackgroundColor:[UIColor greenColor]];

    and sure enough it turned from white to green. I tested this on my phone as well and again no transparency. Using XCode 4.3.2 for iPhone 5.1. Any help is appreciated!!

    • Jon Brown

      Figured it out, it was a different version of the AQGridView from the one used in the tutorial that was causing the issue.

      • Bob

        Hey Jon,

        Could you share how you fixed the background color issue? I’m having problems with that too thanks.

      • http://borkware.com Mark Dalrymple

        I couldn’t reply to Bob below, so replying here :-)

        To fix the colors, I had to change the background color for both the GridViewCell and the contentView. I added this to the end of initWithFrame:

        // Default background color is obliterating the background.
        self.backgroundColor = [UIColor clearColor];
        self.contentView.backgroundColor = [UIColor clearColor];

      • Wazir

        thanx! this work like charm for me

  • http://leonardofrangelli.com Leonardo Frangelli

    Hey Bob,

    Delete the AQGrid from your project and copy from the tutorial.

    I did here and works for me!

    • wgs

      It’s not the problem of version of the AQGridView. You need to add the Classes folder and Resources folder to a folder and drag that folder to you project. You should not add the two folders to a new group in Xcode. This is what I found when trying to debug the problem. But I can’t find the reason at this moment. Is there anybody who knows?

  • Anil

    Hi excellent tutorial. thanks!
    I;’ve run into a problem though. After adding the GridViewCell and GridViewController classes and running g for the first time, where its supposed to show the messed up cells in the grid view, it just shows a blank black screen in my second tab. What am i doing wrong?

  • HongPH

    Excellent tutorial. Thanks U

  • Gif

    Hi there, would the second part of this tutorial work on the simulator? it would be awesome if it could
    thanks

  • Gif

    Hi there, would the second part of this tutorial work on the simulator? it would be awesome if it could
    thank you

  • Gif

    I am realising this second bit is not quite straight forward for a NOOB in xcode, making it clearer having explanations would be priceless. Good tutorial nonetheless

  • http://abelsoul.co.uk Robert

    @Gif:

    It does run on the simulator.
    Regarding being a NOOB, I started learning Xcode on Monday and tried this then.
    Like you, I struggled.
    I decided to do the first two tutorials on dev.apple and come back – things make a lot more sense now.

    @Tope:
    Excellent tutorial. Thank you.

  • Tuan Bui

    Do you need to get feedback on your mobile app? Try http://www.mobosurvey.com that works on both desktop and mobile devices, build your mobile forms/surveys in minutes with a free account now.

  • Michał Gumny

    Hey great tutorial, I actually needed one like this, One thing do, you write “Change the GridViewController.h file and make it a subclass of AQGidViewController” (later in code you subclass you from UIViewController), unfortunately in my case subclassing from AQGidViewController caused that viewDidLoad went to the loop.