Blog

Back to Blog

A Weather Information App: Datasource Helpers and Custom Cells in ShinobiDataGrids

Posted on 24 Jul 2013 Written by Dan Allsop

The ShinobiDataGrid, new in ShinobiGrids version 2.0, provides a more powerful and flexible way of displaying your tabular data than its previous iteration the ShinobiGrid. In this blog post I will be describing how to make the most of the new ShinobiDataGrid using a weather demo app as an example. The weather demo app is a concept app, showing how to obtain weather data from Yahoo’s RSS feed, and use this data to populate a variety of visually interesting custom SDataGridCells.

Weather Demo App

The code for the completed project is available on GitHub and as a zip file. If you do not already have a copy of the ShinobiGrids framework then I encourage you to get yourself a 30 day free trial.

If you’re new to ShinobiGrids I recommend checking out the ShinobiGrids Quick Start Guide before you read on. It’s designed to help walk you through the steps required to add a ShinobiDataGrid to your iOS application. It may also be worth familiarising yourself with the DataGridUserGuide Document, found in the API docs that come bundled with the ShinobiGrids framework. This describes the features of the ShinobiDataGrid and its associated concepts, together with some step-by-step guides.

If you open up the weather demo project in Xcode, you’ll see there are several groups of classes. They are:

  • Images: contains all of the images used in the project, such as colored arrows, and images depicting the various weather types.
  • ShinobiGrids: contains all of the custom cells and datasourceHelperDelegates used by each of the two ShinobiDataGrids in the weather demo application. It is further subdivided into two subgroups, one for each of the two ShinobiDataGrids in the project.
  • WeatherDataObject: contains simple data classes used to hold the weather data.
  • XMLReaders: contains all of the classes used to parse the various forms of XML received from Yahoo.

The weather demo app consists of two grids: _topGrid, situated in the top half of the weather app, displays today’s weather data, and _bottomGrid, situated in the bottom half of the weather app, displays the weather forecast over consecutive days in the near future.

The Datasource Helper

To add data to the ShinobiDataGrids, the app uses the new SDataGridDataSourceHelper, which is a simpler alternative to writing your own datasource. It provides an easy mechanism for rendering an array of data objects within the data-grid, allowing you to specify which of the data object’s properties should be rendered in each column. You can add a datasource helper to ShinobiDataGrids in just 3 easy steps:

Step 1) When initialising the columns in the DataGrids, set the propertyKey for each column at initialization using the -initWithTitle:forProperty: method. The property key is used by the datasource helper to determine which data object property to render within a given column. For example, in the weather demo app, the day/date column in the bottom grid would be defined as follows:

 SDataGridColumn* columnOne = [[SDataGridColumn alloc] initWithTitle:@"Day/Date" forProperty:@"day"];
columnOne.width = _bottomGrid.frame.size.width - 700;
[_shinobiDataGrid addColumn: columnOne];

Step 2) Initialize a datasource helper passing it a reference to the relevant ShinobiDataGrid. For example, the bottom grid in the weather app has its datasource helper defined on line 304 of ViewController.m:

_bottomGridDatasourceHelper = [[SDataGridDataSourceHelper alloc] initWithDataGrid:_bottomGrid];

Step 3) Create an NSArray of data objects and hand it to the datasource helper. In the weather demo, the data is an array of WeatherDataObjects, whose properties are referred to by the propertyKey of each column as defined in step 1. For example, on line 532 of ViewController.m:

NSArray *bottomGridData = [[NSMutableArray alloc] initWithArray:[weatherDataObject listOfWeatherForecastItems]];
_bottomGridDatasourceHelper.data = bottomGridData;

Creating Custom cells

As you can see from the screenshot, the cells in the weather app’s data grid aren’t just simply strings: they include images, multiple lines of text, and more – all generated from a single piece of data provided by the helper. This is where ShinobiGrids’ ability to create your own custom cells really comes into play. One of the simpler examples of a custom cell in the weather app is the SDataGridDayDateCell, which displays the date and day of the week in the bottom data grid:

Day Date Custom Cell

If you open up DayDateCell.h, you’ll see that it is a subclass of SDataGridCell:

#import <Foundation/Foundation.h>
#import <ShinobiGrids/ShinobiDataGrid.h>

// A cell which renders date and day the weather information refers too
@interface SDataGridDayDateCell : SDataGridCell

-(void)setDate:(NSString*)newDate;
-(void)setDay:(NSString*)newDay;

@end

The public methods are used to update the properties of the custom cells, which will cause the UI elements to be updated.

If you now look at DayDateCell.m, you’ll see that there are several important parts to make sure the custom cell displays the data the way we want it. The first is the -initWithReuseIdentifier: method, which adds the required UI elements to the view:

-(id)initWithReuseIdentifier:(NSString *)identifier {
self = [super initWithReuseIdentifier:identifier];

if (self) {

// Create UITextView to display the date
_dateTextView = [UITextView new];
[_dateTextView setBackgroundColor:[UIColor clearColor]];
[_dateTextView setTextAlignment:NSTextAlignmentCenter];
[_dateTextView setTextColor:[UIColor blackColor]];
[_dateTextView setFont:[UIFont fontWithName:@"Helvetica" size:10]];
[_dateTextView setEditable:NO];
[_dateTextView setScrollEnabled:NO];
[_dateTextView setTextColor:[UIColor textColor]];
[self addSubview:_dateTextView];

// Create UIView to give the illusion that the cell is split horizontally
_line = [[UIView alloc] init];
[[_line layer] setBorderWidth:1];
[[_line layer] setBorderColor:[UIColor gridBorderColor].CGColor];
[self addSubview:_line];

// Create UITextView to display the day of the week
_dayTextView = [UITextView new];
[_dayTextView setBackgroundColor:[UIColor clearColor]];
[_dayTextView setTextAlignment:NSTextAlignmentCenter];
[_dayTextView setTextColor:[UIColor blackColor]];
[_dayTextView setFont:[UIFont fontWithName:@"Helvetica" size:40]];
[_dayTextView setEditable:NO];
[_dayTextView setTextColor:[UIColor textColor]];
[self addSubview:_dayTextView];

}

return self;
}

The next part is the –setFrame: method, which ensures that the UI elements are positioned correctly when the frame is computed:

-(void)setFrame:(CGRect)frame{

[super setFrame:frame];

// When the cell frame is set, update the frames of the UIViews it contains 
[_dateTextView setFrame:CGRectMake(0, -5, self.bounds.size.width, 25)];

[_line setFrame:CGRectMake(0, 20, self.bounds.size.width, 1)];

[_dayTextView setFrame:CGRectMake(0, 28, self.bounds.size.width, 100)];

}

The last part is the implementation of the methods defined in the header file, to update the UI elements when the properties are set:

// When the date property is set, update the textview that renders this value
-(void)setDate:(NSString*)newDate{
[_dateTextView setText:newDate];
}

// When the day property is set, update the textview that renders this value
-(void)setDay:(NSString*)newDay{
[_dayTextView setText:[[SDataGridDayDateCell _weekDays] objectForKey:newDay]];
}

After the creation of the custom cell is complete, the next step is to use this cell for a column by setting the cellType property for that column, as demonstrated at line 318 of the ViewController.m class:

[gridColumn setCellType:cellType];

Tying it together

Although the SDataGridDataSourceHelper is able to automatically populate columns that contain SDataGridTextCell instances, to populate your custom cells you need to implement an SDataGridDataSourceHelperDelegate. The BottomGridDataSourceHelperDelegate class in the weather demo is an example of this. The header file declares the protocol:

#import <Foundation/Foundation.h>
#import <ShinobiGrids/ShinobiDataGrid.h>

// DataSourceHelperDelegate for grid containing future weather information
@interface BottomGridDataSourceHelperDelegate : NSObject <SDataGridDataSourceHelperDelegate>

@end

The delegate method you need to implement is dataGridDataSourceHelper:populateCell:withValue:forProperty:propertyKeysourceObject:. The method should determine which column is being populated using the property key, cast the cell to your custom type, and call the custom cell methods to keep it updated at runtime and return YES. However make sure to return NO in cases that you aren’t using custom cells and thus want the helper to populate the cell automatically. In BottomGridDataSourceHelperDelegate, the day date cell is populated as follows:

#import "BottomGridDataSourceHelperDelegate.h"
#import "WeatherForecastItem.h"
#import "SDataGridHighLowCell.h"
#import "SDataGridDayDateCell.h"
#import "SDataGridWeatherCell.h"

#define DAY @"day"
#define CODE @"code"
#define HIGH @"high"

@implementation BottomGridDataSourceHelperDelegate

// Handle adding data to custom cells in our DataGrid ourselves
-(BOOL)dataGridDataSourceHelper:(SDataGridDataSourceHelper *)helper populateCell:(SDataGridCell *)cell withValue:(id)value forProperty:(NSString *)propertyKey sourceObject:(id)object
{
WeatherForecastItem *weatherForecastItem = (WeatherForecastItem*)object;

if([propertyKey isEqualToString:DAY]){
SDataGridDayDateCell *dayDateCell = (SDataGridDayDateCell *)cell;
[dayDateCell setDate:[weatherForecastItem date]];
[dayDateCell setDay:[weatherForecastItem day]]; 
return YES;
}

...

// return 'NO' so that the datasource helper populates all the other cells in the grid.
return NO;
}

@end

Finally make sure to set your newly made SDataGridDataSourceHelperDelegate to be your ShinobiDataGrid’s delegate, for example in line 307 of ViewController.m in the weather app:

_bottomGridDataSourceHelperDelegate = [[BottomGridDataSourceHelperDelegate alloc] init];
_bottomGridDatasourceHelper.delegate = _bottomGridDataSourceHelperDelegate;

There are lots more example of custom cells in the weather demo app – have a browse through the code to get a few ideas of what can be accomplished using custom cells. You may wish to try your hand at making more complex custom cells, and the custom cell is designed to allow you to do just that! We look forward to seeing the variety of weird and wonderful cells you come up with using the ShinobiDataGrid in your apps – please tell us about them!.

Summing It Up

Hopefully as a result of explaining parts of the weather demo application I have provided some insight into how you can achieve something similar in your own apps using ShinobiGrids, whether that be by using the datasource helper to make loading data into a grid easier, or by implementing custom cells which should enable you to give your grids more visual flare.

Back to Blog