/** Customizing moreNavigationController */

An iPhone application can display a maximum of 5 tabs at once. If your application has more than 5 tabs, the infamous moreNavigationController comes into play. This is a subclass of UINavigationController that displays a table of those tabs in a UITabBarController that are not visible on the bottom bar because, well, the way I look at it, you have way too many tabs in your design.ūüėõ

But personal opinion aside, there are times when you (willingly or otherwise) may have to grapple with this controller. I had to recently, and let me tell you, it was not fun finding info on this. So, if you are a fellow hunter/gatherer/coder, rummaging around all those infinite StackOverFlow posts for bits of information on customizing this elusive controller, I hereby present a not-so-perfect guide for taming the beast:

Our goal is to create a basic demo app that looks as follows:

tab0

tab1

customMNC

customConfigure

As always, begin by creating a new XCode project and add a new UIViewController file to the project. I shall call mine MyViewController. Always original, moi.

newFile1 newFile2

So now that we have a controller, we can add some background color along with a label and an NSInteger property, tabNumber, to help us distinguish between the controllers:

#import <UIKit/UIKit.h>

@interface MyViewController : UIViewController
{
    UILabel *tabDetail;
}

@property (nonatomic) NSInteger tabNumber;

- (id)initWithNumber:(NSInteger)number;

@end

The ViewController.m should look like this:

@implementation MyViewController

@synthesize tabNumber;

- (id)initWithNumber:(NSInteger)number
{
    self = [super init];
    if (self) {
        tabNumber = number;
        [self.view setBackgroundColor:[UIColor colorWithRed:189.0f/255.0f green:219.0f/255.0f blue:168.0f/255.0f alpha:1.0f]];
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    //Get the screen dimensions
    CGRect screenBounds = [[UIScreen mainScreen] bounds];
    CGSize screenSize = screenBounds.size;

    tabDetail = [[UILabel alloc] initWithFrame:CGRectMake(screenSize.width/2 - 50.0f , 15.0f, 100.0f, 30.0f)];
    [tabDetail setBackgroundColor:[UIColor clearColor]];
    [tabDetail setTextAlignment:NSTextAlignmentCenter];
    [tabDetail setTextColor:[UIColor whiteColor]];
    [tabDetail setFont:[UIFont fontWithName:@"MarkerFelt-Thin" size:25.0f]];
    [tabDetail setText:[NSString stringWithFormat:@"Tab %d", tabNumber]];

    [self.view addSubview:tabDetail];
}

@end

Import the MyViewController.h file into your AppDelegate.m file. We now have to initialize the tab bar controller and add multiple navigation controllers to it. Each of these navigation controllers will have a MyViewController as its root controller. For simplicity, I use a loop and an NSMutableArray. To change the look of the navigation bars, I am assigning a background image. Alternatively, you can change the tintColor of the bar. Thanks to UIAppearance, changing the properties of navigation bars is now a one line job. At this point, this is how the appDidFinishLaunching method will look:

#import "AppDelegate.h"
#import "MyViewController.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    UITabBarController *tabBarController = [[UITabBarController alloc] init];

    NSMutableArray *viewControllers = [[NSMutableArray alloc] init];

    for (int i =0; i<11; i++) {
        MyViewController *VC = [[MyViewController alloc] initWithNumber:i];
        [VC.navigationItem setTitle:[NSString stringWithFormat:@"Navigation Bar %d",i]];
        [VC.tabBarItem setTitle:[NSString stringWithFormat:@"Tab %d",i]];
        [VC.tabBarItem setImage:[UIImage imageNamed:@"notebook.png"]];//image for tab icon

        UINavigationController *NC = [[UINavigationController alloc] initWithRootViewController:VC];
        [NC.navigationBar setBackgroundImage:[UIImage imageNamed:@"navigationBarBG.png"] forBarMetrics:UIBarMetricsDefault];

        [viewControllers addObject:NC];
    }

    [[UINavigationBar appearance] setTitleTextAttributes:
     [NSDictionary dictionaryWithObjectsAndKeys:
      [UIColor colorWithRed:189.0f/255.0f green:219.0f/255.0f blue:168.0f/255.0f alpha:1.0f], UITextAttributeTextColor,
      [UIFont fontWithName:@"MarkerFelt-Thin" size:16.0f], UITextAttributeFont,nil]];

    [tabBarController setViewControllers:viewControllers];

    [self.window setRootViewController:tabBarController];

    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
 }

Go ahead and run the app on a simulator/device. Click through the tabs one by one and you will notice that while all the tabs themselves are just as they should be, the More tab (which contains a UITableView as shown below) has a mind of its own:

uncustomMNC1

So, this is where the fun part starts. We will now try to make the More tab as consistent with the other tabs as possible. This becomes so much simpler if we work on one feature at a time. First off, we will tackle the navigation bar. For some reason, UIAppearance does not seem to affect the moreNavigationController’s navigation bar, so we have to explicitly set the background image. Add the highlighted lines to your application delegate:

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    .
    .
    .

    //Add this line to change the moreNavigationController's navigation bar image:
    [tabBarController.moreNavigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"navigationBarBG.png"] forBarMetrics:UIBarMetricsDefault];

    //You can change the navigation bar title by adding the following line:
    [[tabBarController.moreNavigationController.viewControllers objectAtIndex:0] setTitle:@"Navigation Bar for More Tab"];

     [self.window setRootViewController:tabBarController];
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}

Run the app now and you will see that the look and feel of the navigation bar for the More tab is now consistent with that of the rest of the navigation bars:

uncustomMNC2

However, the Edit button looks completely out of place here. Sometimes, you may wish to disable editing altogether. In that case, all you have to do to is to set the customizableViewControllers property of the UITabBarController to nil as follows:

    //I'm not doing this here, but you can if you like. This disables the 'Edit' button:
    tabBarController.customizableViewControllers = nil;

I happen to like the Edit option so I will customize the button instead. To do this, we have to implement a UINavigationControllerDelegate method and set our AppDelegate as the delegate for the moreNavigationController. If you are not aware of how delegates work in Objective-C, I strongly recommend that you read up on them. I am a huge fan of delegation because it makes life that much simpler. For now though, you should at least understand that, “a delegate allows one object to send messages to another object when an event happens.“ If you are from a Java background, I like to think of a delegate simply as an event listener.

So first off, set the AppDelegate as a UINavigationControllerDelegate, UITabBarControllerDelegate and UITableViewDataSource. We need UINavigationControllerDelegate methods to customize the Edit button, UITabBarControllerDelegate methods to make changes to the Configure screen(which pops up when you tap Edit) and UITableViewDataSource methods to make changes to the moreNavigationController‘s table cells. This is what the AppDelegate.h must look like now:

@interface AppDelegate : UIResponder <UIApplicationDelegate, UINavigationControllerDelegate, UITabBarControllerDelegate, UITableViewDataSource>
{
    id originalDataSource;
}
@property (strong, nonatomic) UIWindow *window;

@end

Then, in AppDelegate.m, set the moreNavigationController‘s delegate to self and implement the navigationController:willShowViewController:animated: method as follows:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    UITabBarController *tabBarController = [[UITabBarController alloc] init];

    .
    .
    .

   //Add this line to modify the 'Edit' button
    [tabBarController.moreNavigationController setDelegate:self];

    [self.window setRootViewController:tabBarController];
     self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
 }

- (void)navigationController:(UINavigationController *)navigationController  willShowViewController:(UIViewController *)viewController  animated:(BOOL)animated
{
    UINavigationBar *moreNavBar = navigationController.navigationBar;
    UINavigationItem *moreNavItem = moreNavBar.topItem;
    moreNavItem.rightBarButtonItem.tintColor = [UIColor whiteColor]; // Set color
    [moreNavItem.rightBarButtonItem setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                                                            [UIColor colorWithRed:57.0f/255.0f green:95.0f/255.0f blue:35.0f/255.0f alpha:1.0f], UITextAttributeTextColor,
                                                            [UIFont fontWithName:@"MarkerFelt-Thin" size:16.0f], UITextAttributeFont,nil] forState:UIControlStateNormal];
    [moreNavItem.rightBarButtonItem setTitle:@"Re-arrange"];// Set edit button title

}

If you run the app again, you will notice that the Edit button now has its shine on. ‚ėļ

uncustomMNC3

Next, we will tackle the table view that lists our ‚Äúextra‚ÄĚ tabs. This is easy to do once you understand that the topViewController property of the moreNavigationController gives you access to the UITableViewController. We can now modify the UITableViewController‚Äôs view like any other UITableView:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    UITabBarController *tabBarController = [[UITabBarController alloc] init];

    .
    .
    .

    //Set title
    [[tabBarController.moreNavigationController.viewControllers objectAtIndex:0] setTitle:@"Navigation Bar for More Tab"];

    //Set background
    [tabBarController.moreNavigationController.topViewController.view setBackgroundColor: [UIColor colorWithRed:189.0f/255.0f green:219.0f/255.0f blue:168.0f/255.0f alpha:1.0f]];

    //Set table separator style
    [(UITableView *)tabBarController.moreNavigationController.topViewController.view setSeparatorStyle:UITableViewCellSeparatorStyleNone];

    [self.window setRootViewController:tabBarController];
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}

But this code above will only change the background and seperator of the table.

uncustomMNC4

What if we wish to change table cell details like font, text color, etc? Well, there are 2 ways to go about this:

  1. The first method is shorter and gives us limited control over the table cells. Simply access the cells via the visibleCells property of the table. But there are some things like removing accessoryView which are downright impossible to do this way, since as soon as you scroll the table it will redraw its cells all over again!
    //Avoid using this method - it is unreliable
    for (UITableViewCell *cell in [(UITableView *)tabBarController.moreNavigationController.topViewController.view visibleCells]) {
    
            [cell.textLabel setFont:[UIFont fontWithName:@"MarkerFelt-Thin" size:20.0f]];
            [cell.textLabel setTextColor:[UIColor whiteColor]];
            [cell setAccessoryType:UITableViewCellAccessoryNone];
            [cell setAccessoryView:nil];
        }
  2. The second method involves implementing the UITableViewDataSource protocol. We create a variable to hold the original data source of the moreNavigationController, assign the AppDelegate as the data source for the moreNavigationController and implement UITableViewDataSource methods as below. This ensures that even if the user scrolls the moreNavigationController’s table, the cells will be redrawn just the way we want them.
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    
        UITabBarController *tabBarController = [[UITabBarController alloc] init];
    
        .
        .
        . 
    
        [tabBarController.moreNavigationController.topViewController.view setBackgroundColor: [UIColor colorWithRed:189.0f/255.0f green:219.0f/255.0f blue:168.0f/255.0f alpha:1.0f]];
        [(UITableView *)tabBarController.moreNavigationController.topViewController.view setSeparatorStyle:UITableViewCellSeparatorStyleNone];
    
        //This way, the cells will be redrawn correctly on scrolling
        [tabBarController.moreNavigationController setDelegate:self];
        originalDataSource = [(UITableView *)tabBarController.moreNavigationController.topViewController.view dataSource];
        [(UITableView *)tabBarController.moreNavigationController.topViewController.view  setDataSource:self];
    
        [self.window setRootViewController:tabBarController];
        self.window.backgroundColor = [UIColor whiteColor];
        [self.window makeKeyAndVisible];
        return YES;
     }
    
    -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return [originalDataSource tableView:tableView numberOfRowsInSection:section];
    }
    
    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
         UITableViewCell *cell = [originalDataSource tableView:tableView cellForRowAtIndexPath:indexPath];
         cell.accessoryType = UITableViewCellAccessoryNone;   
        [cell.textLabel setFont:[UIFont fontWithName:@"MarkerFelt-Thin" size:20.0f]];
        [cell.textLabel setTextColor:[UIColor whiteColor]];
        [cell.imageView setAlpha:0.5f];
    
       return cell;
    }

customMNC

All that remains now is to fix the Configure controller:

uncustomMNC5

To do so, set , we assign the AppDelegate to be the tab bar controller’s delegate and implement the tabBarController:willBeginCustomizingViewControllers: method. Some folks claim this may not work all the time. This code works on both the simulator and my iPhone 5 test device, but I would still advise caution when implementing this.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    UITabBarController *tabBarController = [[UITabBarController alloc] init];

    .
    .
    .

    originalDataSource = [(UITableView *)tabBarController.moreNavigationController.topViewController.view dataSource];
    [(UITableView *)tabBarController.moreNavigationController.topViewController.view  setDataSource:self];

    //This helps us customize the 'Configure' screen
    [tabBarController setDelegate:self];

    [self.window setRootViewController:tabBarController];
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}

- (void)tabBarController:(UITabBarController *)controller willBeginCustomizingViewControllers:(NSArray *)viewControllers {

    UIView *editViews = [controller.view.subviews objectAtIndex:1];
    UINavigationBar *editModalNavBar = [editViews.subviews objectAtIndex:0];

    [editModalNavBar setBackgroundImage:[UIImage imageNamed:@"navigationBarBG.png"] forBarMetrics:UIBarMetricsDefault];

     UINavigationItem *modalNavItem =editModalNavBar.topItem;
    modalNavItem.rightBarButtonItem.tintColor = [UIColor whiteColor]; //Set color.
    [modalNavItem.rightBarButtonItem setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                                                            [UIColor colorWithRed:57.0f/255.0f green:95.0f/255.0f blue:35.0f/255.0f alpha:1.0f], UITextAttributeTextColor,
                                                            [UIFont fontWithName:@"MarkerFelt-Thin" size:16.0f], UITextAttributeFont,nil] forState:UIControlStateNormal];
    [modalNavItem.rightBarButtonItem setTitle:@"Save Changes"];//Set bar button title.

    [[controller.view.subviews objectAtIndex:1] setBackgroundColor:[UIColor colorWithRed:189.0f/255.0f green:219.0f/255.0f blue:168.0f/255.0f alpha:1.0f]];

    editModalNavBar.topItem.title = @"Re-arrange Tabs";//Set title
}

customConfigure

Well, that‚Äôs it then. Build and see for yourself – not only the moreNavigationController‚Äôs table but also the Configure view looks much better, IMHO. ¬†These are all hacks and tricks I’ve gathered after searching the internet for my last application, so suggestions and comments are always welcome.

Happy coding! ‚ėļ

Why Evolution Is True

From BBC Science News via a series of tweets, including Barbara King, Steve Ashley, and finally an email from Matthew Cobb, an amazing fossil finds its way to us.

As reported by Nick Crumpton, a fossil ‚Äúdeath march‚ÄĚ of a horseshoe crab was found in the Solenhofen limestone‚ÄĒthe same formation that yielded the famous transitional fossil Archaopteryx.¬† The fine-grained sediments from what was once a quiet lagoon produced exquisite preservation, and in this case we have what is interpreted as the final walk of a horseshoe crab flung into the lagoon by a storm (the storm part is speculative) 150 million years ago.¬† Here‚Äôs the animal:

Note the phenotypic similarity to modern horseshoe crabs, a similarity which makes this animal a famous ‚Äúliving fossil.‚ÄĚ Of course they‚Äôre not externally identical to modern ones, and we know nothing about the changes in its anatomy, biochemistry, or simply DNA‚Ķ

View original post 296 more words

/** Core Plot – 2 : Making a Bar Plot */

This is my second post on the Core Plot framework. In the first one, I talked about¬†setting up your app to use this framework. In this one, I’ll show you how to make a simple bar plot.

In the Project Navigator, right click (or ctrl + click) on your project’s yellow folder and create a New File. Make it a UIViewController subclass (do check the box next to with XIB for User Interface) called BarPlotViewController.

Go to the app’s delegate interface and add an object of BarPlotViewController, as a property. We will call this umm,¬†barPlotViewController. Ha, how very creative.

#import <UIKit/UIKit.h >
#import "BarPlotViewController.h"

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) BarPlotViewController *barPlotViewController;

@end

In the app delegate’s implementation,

1) Synthesize barPlotViewController.
2) Initialize and set it as the root controller for the window.
3) Follow good memory management practices by releasing it within dealloc.

#import "AppDelegate.h"

@implementation AppDelegate

@synthesize window = _window;
@synthesize barPlotViewController;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];

    barPlotViewController = [[BarPlotViewController alloc] init];
    [self.window setRootViewController:barPlotViewController];
    [self.window makeKeyAndVisible];
    return YES;
}

.
.
.

- (void)dealloc
{
    [barPlotViewController release];
    [_window release];
    [super dealloc];
}

@end

It is necessary ¬†to understand that the most important class we will use is the CPTXYGraph (a subclass of CPTGraph), which “holds” all the components of a graph: a set of axes, ¬†an area/frame for the graph, a space within this area to draw the graph on and the actual graph/plot drawing itself.¬†A CPTXYGraph object in itself will not do, however. A view is needed to place this object in, in other words, to “host” the graph, so that it can be displayed on the screen. This functionality is provided by the CPTGraphHostingView class.

Set BarPlotViewController as a CPTBarPlotDataSource as well as a CPTBarPlotDelegate.  Add 3 properties: data (an array to hold bar information), graph (a CPTXYGraph) and hostingView (a CPTGraphHostingView). Also, add a function generatePlot where you will create the bar graph. This is how BarPlotViewController.h will look like:

#import <UIKit/UIKit.h>
#import "CorePlot-CocoaTouch.h"

@interface BarPlotViewController : UIViewController 
<CPTBarPlotDataSource, CPTBarPlotDelegate>

@property (nonatomic, retain) NSMutableArray *data;
@property (nonatomic, retain) CPTGraphHostingView *hostingView;
@property (nonatomic, retain) CPTXYGraph *graph;

- (void) generateBarPlot;

@end

There are several properties you will need to set for graph (think axis lengths, intervals, bar heights and stuff). I prefer using macros instead of setting them on the fly.

@implementation BarPlotViewController

#define BAR_POSITION @"POSITION"
#define BAR_HEIGHT @"HEIGHT"
#define COLOR @"COLOR"
#define CATEGORY @"CATEGORY"

#define AXIS_START 0
#define AXIS_END 50

@synthesize data;
@synthesize graph;
@synthesize hostingView;

.
.
.

Next, generate the data in¬†initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil. For simplicity, we’ll hard code it (not my favorite way of doing things but it’ll do for now).

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {

     self.data = [NSMutableArray array];

     int bar_heights[] = {20,30,10,40};
      UIColor *colors[] = {
            [UIColor redColor],
            [UIColor blueColor],
            [UIColor orangeColor],
            [UIColor purpleColor]};
     NSString *categories[] = {@"Plain Milk", @"Milk + Caramel", @"White", @"Dark"};

     for (int i = 0; i < 4 ; i++){
         double position = i*10; //Bars will be 10 pts away from each other
         double height = bar_heights[i];

         NSDictionary *bar = [NSDictionary dictionaryWithObjectsAndKeys:
                                 [NSNumber numberWithDouble:position],BAR_POSITION,
                                 [NSNumber numberWithDouble:height],BAR_HEIGHT,
                                 colors[i],COLOR,
                                 categories[i],CATEGORY,
                                 nil];
         [self.data addObject:bar];

        }
        [self generateBarPlot];
    }
    return self;
}

Now add the function generatePlot and copy-paste the following code into it.

- (void)generateBarPlot
{
  //Create host view
  self.hostingView = [[CPTGraphHostingView alloc] 
  initWithFrame:[[UIScreen mainScreen]bounds]];
  [self.view addSubview:self.hostingView];

  //Create graph and set it as host view's graph
  self.graph = [[CPTXYGraph alloc] initWithFrame:self.hostingView.bounds];
  [self.hostingView setHostedGraph:self.graph];

  //set graph padding and theme
  self.graph.plotAreaFrame.paddingTop = 20.0f;
  self.graph.plotAreaFrame.paddingRight = 20.0f;
  self.graph.plotAreaFrame.paddingBottom = 70.0f;
  self.graph.plotAreaFrame.paddingLeft = 70.0f;
  [self.graph applyTheme:[CPTTheme themeNamed:kCPTDarkGradientTheme]];

  //set axes ranges
  CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)self.graph.defaultPlotSpace;
  plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:
                        CPTDecimalFromFloat(AXIS_START)
                        length:CPTDecimalFromFloat((AXIS_END - AXIS_START)+5)];
  plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:
                        CPTDecimalFromFloat(AXIS_START)
                        length:CPTDecimalFromFloat((AXIS_END - AXIS_START)+5)];

  CPTXYAxisSet *axisSet = (CPTXYAxisSet *)self.graph.axisSet;
  //set axes' title, labels and their text styles
  CPTMutableTextStyle *textStyle = [CPTMutableTextStyle textStyle];
  textStyle.fontName = @"Helvetica";
  textStyle.fontSize = 14;
  textStyle.color = [CPTColor whiteColor];
  axisSet.xAxis.title = @"CHOCOLATE";
  axisSet.yAxis.title = @"AWESOMENESS";
  axisSet.xAxis.titleTextStyle = textStyle;
  axisSet.yAxis.titleTextStyle = textStyle;
  axisSet.xAxis.titleOffset = 30.0f;
  axisSet.yAxis.titleOffset = 40.0f;
  axisSet.xAxis.labelTextStyle = textStyle;
  axisSet.xAxis.labelOffset = 3.0f;
  axisSet.yAxis.labelTextStyle = textStyle;
  axisSet.yAxis.labelOffset = 3.0f;
  //set axes' line styles and interval ticks
  CPTMutableLineStyle *lineStyle = [CPTMutableLineStyle lineStyle];
  lineStyle.lineColor = [CPTColor whiteColor];
  lineStyle.lineWidth = 3.0f;
  axisSet.xAxis.axisLineStyle = lineStyle;
  axisSet.yAxis.axisLineStyle = lineStyle;
  axisSet.xAxis.majorTickLineStyle = lineStyle;
  axisSet.yAxis.majorTickLineStyle = lineStyle;
  axisSet.xAxis.majorIntervalLength = CPTDecimalFromFloat(5.0f);
  axisSet.yAxis.majorIntervalLength = CPTDecimalFromFloat(5.0f);
  axisSet.xAxis.majorTickLength = 7.0f;
  axisSet.yAxis.majorTickLength = 7.0f;
  axisSet.xAxis.minorTickLineStyle = lineStyle;
  axisSet.yAxis.minorTickLineStyle = lineStyle;
  axisSet.xAxis.minorTicksPerInterval = 1;
  axisSet.yAxis.minorTicksPerInterval = 1;
  axisSet.xAxis.minorTickLength = 5.0f;
  axisSet.yAxis.minorTickLength = 5.0f;

  // Create bar plot and add it to the graph
  CPTBarPlot *plot = [[CPTBarPlot alloc] init] ;
  plot.dataSource = self;
  plot.delegate = self;
  plot.barWidth = [[NSDecimalNumber decimalNumberWithString:@"5.0"]
                     decimalValue];
    plot.barOffset = [[NSDecimalNumber decimalNumberWithString:@"10.0"]
                      decimalValue];
  plot.barCornerRadius = 5.0;
  // Remove bar outlines
  CPTMutableLineStyle *borderLineStyle = [CPTMutableLineStyle lineStyle];
  borderLineStyle.lineColor = [CPTColor clearColor];
  plot.lineStyle = borderLineStyle;
  // Identifiers are handy if you want multiple plots in one graph
  plot.identifier = @"chocoplot";
  [self.graph addPlot:plot];
  [plot release];
}

I know it seems long and scary, but look a little closer and you’ll see it’s actually very simple. Lets take it one step at a time.

First, we create the hostingView to hold the graph. Next, we create the graph itself and add it to hostingView. But because you want a nice, neat looking graph and not just a plain Jane one, you have to do things like set it’s padding and apply a theme. I have chosen a dark gradient theme but there are some 5 or so different ones to choose from. Alternatively, you can also skip this and apply your own background to graph.

//set graph padding and theme
    self.graph.plotAreaFrame.paddingTop = 20.0f;
    self.graph.plotAreaFrame.paddingRight = 20.0f;
    self.graph.plotAreaFrame.paddingBottom = 70.0f;
    self.graph.plotAreaFrame.paddingLeft = 70.0f;
    [self.graph applyTheme:[CPTTheme themeNamed:kCPTDarkGradientTheme]];

Another thing you need to do is specify the range for the x and y axes.

//set axes ranges
    CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)self.graph.defaultPlotSpace;
    plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:
                        CPTDecimalFromFloat(AXIS_START)
                        length:CPTDecimalFromFloat((AXIS_END - AXIS_START)+5)];
    plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:
                        CPTDecimalFromFloat(AXIS_START)
                        length:CPTDecimalFromFloat((AXIS_END - AXIS_START)+5)];

I have added the extra 5 points so that should one of the bars’ position or tip touch the max axis value (which is 50 in this case), it will still be drawn within the axis’ length. Next, customize the axis properties:

CPTMutableTextStyle *textStyle = [CPTMutableTextStyle textStyle];
    textStyle.fontName = @"Helvetica";
    textStyle.fontSize = 14;
    textStyle.color = [CPTColor whiteColor];
    axisSet.xAxis.title = @"CHOCOLATE";
    axisSet.yAxis.title = @"AWESOMENESS";
    axisSet.xAxis.titleTextStyle = textStyle;
    axisSet.yAxis.titleTextStyle = textStyle;
    axisSet.xAxis.titleOffset = 30.0f;
    axisSet.yAxis.titleOffset = 40.0f;
    axisSet.xAxis.labelTextStyle = textStyle;
    axisSet.xAxis.labelOffset = 3.0f;
    axisSet.yAxis.labelTextStyle = textStyle;
    axisSet.yAxis.labelOffset = 3.0f;
    //set axes' line styles and interval ticks
    CPTMutableLineStyle *lineStyle = [CPTMutableLineStyle lineStyle];
    lineStyle.lineColor = [CPTColor whiteColor];
    lineStyle.lineWidth = 3.0f;
    axisSet.xAxis.axisLineStyle = lineStyle;
    axisSet.yAxis.axisLineStyle = lineStyle;
    axisSet.xAxis.majorTickLineStyle = lineStyle;
    axisSet.yAxis.majorTickLineStyle = lineStyle;
    axisSet.xAxis.majorIntervalLength = CPTDecimalFromFloat(5.0f);
    axisSet.yAxis.majorIntervalLength = CPTDecimalFromFloat(5.0f);
    axisSet.xAxis.majorTickLength = 7.0f;
    axisSet.yAxis.majorTickLength = 7.0f;
    axisSet.xAxis.minorTickLineStyle = lineStyle;
    axisSet.yAxis.minorTickLineStyle = lineStyle;
    axisSet.xAxis.minorTicksPerInterval = 1;
    axisSet.yAxis.minorTicksPerInterval = 1;
    axisSet.xAxis.minorTickLength = 5.0f;
    axisSet.yAxis.minorTickLength = 5.0f;

Finally, create an actual CPTBarPlot and add it to graph.

// Create bar plot and add it to the graph
    CPTBarPlot *plot = [[CPTBarPlot alloc] init] ;
    plot.dataSource = self;
    plot.delegate = self;
    plot.barWidth = [[NSDecimalNumber decimalNumberWithString:@"5.0"]
                     decimalValue];
    plot.barOffset = [[NSDecimalNumber decimalNumberWithString:@"10.0"]
                      decimalValue];
    plot.barCornerRadius = 5.0;
    // Remove bar outlines
    CPTMutableLineStyle *borderLineStyle = [CPTMutableLineStyle lineStyle];
    borderLineStyle.lineColor = [CPTColor clearColor];
    plot.lineStyle = borderLineStyle;

    // Identifiers are handy if you want multiple plots in one graph
    plot.identifier = @"chocoplot";

    [self.graph addPlot:plot];
    [plot release];

The last thing you have to do is implement some CPTBarPlotDataSource and CPTBarPlotDelegate methods so that the plot fetches data correctly. Add these methods to BarPlotViewController.m one by one:

1) The first method helps set the number of bars in the plot. The number of bars should be equal to the number of objects in the array data.

-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot
{
    if ( [plot.identifier isEqual:@"chocoplot"] )
    return [self.data count];

    return 0;
}

2) The second one defines each bar’s height and location. These have also been defined in the array data.

-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index
{
    if ( [plot.identifier isEqual:@"chocoplot"] )
    {
        NSDictionary *bar = [self.data objectAtIndex:index];

        if(fieldEnum == CPTBarPlotFieldBarLocation)
            return [bar valueForKey:BAR_POSITION];
        else if(fieldEnum ==CPTBarPlotFieldBarTip)
            return [bar valueForKey:BAR_HEIGHT];
    }
    return [NSNumber numberWithFloat:0];
}

3) Next,  set a label for each bar.

-(CPTLayer *)dataLabelForPlot:(CPTPlot *)plot recordIndex:(NSUInteger)index
{
    if ( [plot.identifier isEqual: @"chocoplot"] )
    {
        CPTMutableTextStyle *textStyle = [CPTMutableTextStyle textStyle];
        textStyle.fontName = @"Helvetica";
        textStyle.fontSize = 14;
        textStyle.color = [CPTColor whiteColor];

        NSDictionary *bar = [self.data objectAtIndex:index];
        CPTTextLayer *label = [[[CPTTextLayer alloc] initWithText:[NSString stringWithFormat:@"%@", [bar valueForKey:@"CATEGORY"]]] autorelease];
        label.textStyle =textStyle;

        return label;
    }

    CPTTextLayer *defaultLabel = [[[CPTTextLayer alloc] initWithText:[NSString stringWithString:@"Label"]] autorelease];
    return defaultLabel;

}

If you run the app at this point, a nice little graph is produced but something is amiss…We haven’t filled color into the bars yet!

4) So add one last method:

-(CPTFill *)barFillForBarPlot:(CPTBarPlot *)barPlot
recordIndex:(NSUInteger)index
{
    if ( [barPlot.identifier isEqual:@"chocoplot"] )
    {
        NSDictionary *bar = [self.data objectAtIndex:index];
        CPTGradient *gradient = [CPTGradient gradientWithBeginningColor:[CPTColor whiteColor]
        endingColor:[bar valueForKey:@"COLOR"]
        beginningPosition:0.0 endingPosition:0.3 ];
        [gradient setGradientType:CPTGradientTypeAxial];
        [gradient setAngle:320.0]; 

        CPTFill *fill = [CPTFill fillWithGradient:gradient];

        return fill;

    }
    return [CPTFill fillWithColor:[CPTColor colorWithComponentRed:1.0 green:1.0 blue:1.0 alpha:1.0]];

}

I’ve used a gradient fill for the bars but if you don’t like that, just replace the line

CPTFill *fill = [CPTFill fillWithGradient:gradient];

with the line

CPTFill *fill = [CPTFill fillWithColor:[bar valueForKey:@"COLOR"]];

And the moment has arrived. Run the app and there it should be – your own colorful little baby!ūüôā

See, I told you it wasn’t that hard. But this isn’t it – there’s a LOT more fun stuff you can do with Core Plot. The best place to start is the source code of the framework itself. So go ahead and explore to your heart’s content. Happy coding!ūüôā

/** Core Plot – 1: Getting Started */

Recently, I had to use graphs in my iPad app and was told to check out the Core Plot framework. I found it hard to get much info initially and many of the tuts seemed outdated. So I thought I’d make some instead.

Turns out once you get your head around it, Core Plot is a pretty awesome framework. It uses Core Animation, Core Data, and Cocoa Bindings as its building blocks and lets you create graphs and charts in 2D only. So if you’re interested in 3D charts, you’d better look somewhere else. But all in all, this is a good, active API to get the (2D) job done.¬†In this post, I’m only going to talk about how to setup your app for all the awesome code that’ll go in it. My¬†next post describes how to create a bar chart.

First of all, try to go through the wiki for the framework. It’s not much and is well explained but if you’re really short on time, make sure you at least read the Core Plot Design Overview, because YOU WILL BE LOST otherwise.

Once you’re done only skimming the wiki (what, you thought I wouldn’t know?) download the newest release of Core Plot from here and put the folder somewhere easily accessible…like um, your desktop, maybe? Yea, I like being Captain Obvious. ^.^

Now open up Xcode and create a new window-based project. Call it whatever the heck you want. I’m gonna call mine Bars, because my next post will be about creating a custom bar chart with Core Plot (Note : If you want to create only a simple line graph, then John Wordsworth’s tutorial is the place to go).

Once your project is created, open the finder and in the root directory of your project, create a new folder called CorePlot. Now open the CorePlot folder and go to Binaries and within that open the iOS folder. This will have two things in it : libCorePlot-CocoaTouch.a and a folder named CorePlotHeaders. Copy and paste both of these one at a time into the new folder you just created.

Next, drag this new folder onto the topmost tab in the project navigator in Xcode(the one that mentions your project’s name, target(s) , SDK and has a blue Xcode project icon next to it). I usually uncheck the box next to Copy items into destination group’s folder. But it’s no rule. Your project directory should now look like this:

Next, click on the topmost tab in the project navigator (the same one that mentions your project’s name, etc. and has a blue Xcode project icon next to it). Under Build Settings, in the search box, type ‘Other Linker Flags’ and add the entries -ObjC and -all_load.

Now there’s only one last thing left to do. Under Build Phases, we have to add the QuartzCore framework to the list that says Link Binary With Libraries. The list will already have three frameworks listed. To add one more, click on the ‘+‘ button under it and select the QuartzCore framework.

With that, we have successfully added Core Plot to our app. Now you can use the framework to create graphs and charts, but don’t forget to import it (#import <CorePlot/CorePlot.h>)¬†in whichever file you wish to use it’s classes!

The next post¬†explains how to make a simple, customized bar graph using this framework. Ok then, happy coding!ūüôā

/** Changing BlackBerry JRE to an Older Version (Eclipse Plug-in) */

 

One of the most important things every BB developer needs to know is how to make an app that’s been created with a newer SDK run on older OS versions. Now most people will tell you that if you want your app¬†to¬†run on multiple¬†OS¬†targets, the smartest thing to do is just start with the lowest OS. And they’re right.¬†The thing is,¬†I don’t know about you, but I can’t recall the last time I did everything by the book. So if you’re like me – less planning, more dive-right-in types and just realized that¬†the app you made with SDK 6.0.0¬†now also¬†has to run on OS 5 (or below), what do you do? The answer is – a hell¬†load of sometimes totally inexplicable things.¬†Still, have faith, as it’s difficult, but not impossible.

So, first things first. BB apps are not backward compatible by default. Hence we need to check if any of our code contains APIs or other stuff not provided in JDE 5.

If you have an already downloaded sim that runs on OS 5 (like 9700/8900/9550) try running the app on that sim. Chances are, it’s gonna crash. But if it doesn’t, you have an app¬†that has no APIs new to 5 (you lucky dog). No, this doesn’t mean your¬†app will magically run on OS 5, but hey, atleast it’s less work! As for the rest of us, it’s time to get rid of those APIs. But we can only do that if we know what APIs are and aren’t conflicting. That means, running/debugging with the appropriate JRE.

This is done by changing the JRE as follows:

  1. Find the execution environment file by going to the root folder where you installed the plug-in -> plugins -> net.rim.ejde.componentpack5.0.0_5.0.0.25¬†(or whichever version you wanna check with) -> components -> BlackBerry(.ee file). You can face two problems here : either there’s no component pack in the plugins folder or, there’s no BlackBerry.ee file. In the first case, just¬†download the¬†component package from here¬†and¬†then extract it in the¬†plugins folder. In the second case, just go to the folder of the¬†default pack you use¬†(net.rim.ejde.componentpack6.0.0_6.0.0.30¬†in my case) -> components and copy-paste the BlackBerry.ee file from here into the components folder of the pack you want to use. Now open and Edit BlackBerry.ee file with appropriate with 5.0 text like..-Dee.name=BlackBerry JRE 6.0.0 to -Dee.name=BlackBerry JRE 5.0.0 or what ever JRE you want to install.
  2. Go to Windows–>Preferences–>Java–>Installed JREs.
  3. Click on the Add Button,a dialog screen appears – click on ‘BB Execution Environment VM’. Click on the File button to open the edited BlackBerry.ee file in the correct component pack’s components folder.
  4. Click on Next or Finish Button. This will add the JRE to your Eclipse..
  5. ¬†Now to change the JRE just¬†open Run/Debug Configurations (under Run or Debugūüėõ )and click on the tab JRE. Choose the Alternate JRE which you want to select for your project. Now you can fix all the errors in your code – stuff that doesn’t go with the older OS!

Now simply sign your project (if using secure APIs) and then package it. Your project is now ready to run on¬†an older device!ūüėÄ Until next time, happy coding!

 

//JVM error 545

One (not so) fine day, I was asked to merge the¬†two¬†halves of a¬†BB app, both created seperately by two different people. This wasn’t really new territory to me and since I’d “been-there-done-that” before, I figured it would be a piece of cake.¬†Of course, that’s just wishful thinking.¬† See, the thing is, here I am happily¬†marrying the two apps and all of¬† a sudden my sim goes all “gotcha!!” on me¬†with¬†the message :

 

JVM error 545 : Incompatible or Corrupt Filesystem

RESET

Clicking on the RESET¬†option¬†does *drummm roollll* NOTHING! Ha! Well, this is¬†BlackBerry we’re talking about, you know.¬†What did you expect, fireworks and violins?¬†But don’t worry because this is a VERY common error that pops up not only on simulators but even actual¬†devices. Here’s how you solve it: Go to your¬†root installation directory (you know, the one where you stored your plug-in ) -> plugins ->¬†choose the correct component pack ->¬†components -> simulator¬† and then find the clean.bat file and run it. And that’s it – problem solved! In case you couldn’t locate the clean.bat file, just find and delete all the *.dmp files and you’re good to go.¬†So now can you see the fireworks and hear the violins, after all?ūüėČ

/** Things to Know Before Learning Objective C */

Hi guys! So I’ve¬†been learning Objective C recently and most tuts are a bit confusing. When I learnt C++,¬†it was from the ground up –¬†it took a LOT of time but what I learnt¬†5 years ago is still fresh in my mind. I think it’s because¬†the stronger your¬†understanding of¬†¬†the going-ons (or as I like to say “magic”ūüėÄ ) behind something,¬†the more¬†it becomes¬†a¬†part of your natural¬†thinking process. Most of the guides¬†I came across were¬†either aimed at ‘jumpstarting’ or were just too baffling for my simple mind.¬†Although I caught up eventually, there are still some things¬†I feel that anyone¬†new to Objective C¬†should know beforehand:

      1. IT’S A TYPE OF C: Objective C is a just a layer on top of the C language. So if you know C or C++ beforehand, you’re in luck. Somewhat. If¬† you’ve never used any of these before,¬†I’d say cover the basics of¬†C before you begin with ObjC. Print statements, ¬†datatypes, getting user input, alloc/malloc¬†and pointers –¬†these¬†five topics¬†are musts. It’s really complicated stuff- nah, I’m just messing with you. :D¬†Infact the only thing that you might struggle with are pointers. This is a great place to start.
      2. ¬†OBJECTS AND CLASSES (DUH, RIGHT?): Well, I’m being a real Captain Obvio here but¬†you never know. So¬†like I said before, Objective C = C + (classes, objects, et all.)¬†. The funny thing is, if you know only C and no OOP-languages, you will absolutely need to understand what objects and classes are because these will be new to you.¬†And if you’ve done ¬†only C++, be prepared for some serious differences in syntax! If you’ve done both, welome to the gang mate!
      3. ¬†OBJECTIVE C IS FULL OF POINTERS :¬†Yup, they’re everywhere. Infact, an object variable is always declared¬†as a pointer in ObjC. So now might be a good time to catch¬†up on the concept of pointer variables (see (1)¬†).
      4. ¬†CLASS = INTERFACE + IMPLEMENTATION: Objective C requires us to first¬†declare¬†the outline or ‘blueprint’¬†of the class and then implement all the methods in it. Here’s an example:¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬†¬† ¬†¬†@interface myClass : superClass {¬†int member_variable; }¬†-(void)¬† member_function1; // without arguments-(void)¬† member_function2: (int) argument; // with 1¬†argument

        @end //interface ends

         

        @implementation myClass 

        (void)  member_function1

        { //a lil magic here! }

         (void)  member_function2: (int) argument

        { // lil more abracadabra here! }

        @end //implementation ends

         

        int main (int argc, char * argv[]){

        //code

        }

      5. SPLITTING CODE IS GOOD: I love it when a language provides a way to make code less messy. Objective C allows you to store a class’ interface and¬†implementation, and the main function in three separate files.
      6. ¬†NSAUTORELEASEPOOL:¬†Quite a mouthful there. The first line in a ObjC¬†program’s main() function is always this:

NSAutoreleasePool * pool = [[ NSAutoreleasePool alloc ] init ];

This is a line that simply requests a small part or ‘pool’ of memory to be set aside for the program. It is actually¬†a shortened form of¬†¬†¬†¬† the following statements:

NSAutoreleasePool * pool; //declaring a NSAutoreleasePool object called pool

pool = [ NSAutoreleasePool alloc ]; //requesting for memory to be allocated

[pool  init ]; //initializing this object

At the end of the main() function, just before the return statement, there must be a line that says:

[pool drain]; //releasing all the held up memory because we dont need it anymore

Now, if you’re wondering why this has to be done, here’s why: If¬†it weren’t for¬†NSAutorelease¬†class, we’d probably have to¬†do memory management manually, for each and every object we create. And everyone knows that’s a bad idea.

Well, that’s it for now. Hope this helps you guys! Happy learning!ūüėÄ

/** RSS feeds + XML Http Requests (HTTPClient) with Titanium Appcelerator */

An XML HTTP Request (xhr) is nothing but a simple HTTP or HTTPS request to a web server to get a response from the server in either xml format or just plain text. There are many things one can do with this data. If the HTTP request was directed to an RSS (Really Simple Syndication) feed url, for instance, we can incorporate the feed in our app. RSS is a web format used to publish frequently updated blog entries, news headlines, audio, and video on many websites.

To this end, Titanium provides Titanium.Network.HTTPClient. By calling Titanium.Network.createHTTPClient we can get a HTTPClient object that we will use to make requests and receive respones. To display the feed, we will make use of Titanium.UI.TableView. The first thing to do is to create our HTTPClient, open it and create an empty data object that will later hold the data for our table.

var data = [];

var xhr = Ti.Network.createHTTPClient();

xhr.open(“GET”,’http://www.nytimes.com/services/xml/rss/nyt/GlobalHome.xml&#8217;);

The open() function takes two parameters – the first is the type of call we wish to make to the server (‘GET’ means we want to read data from the url) and the second is the URL of the page we want to contact (this is usually what appears in the address bar of your browser when you open the page). The URL I’m using is the link to a New York Times RSS feed.

So now we have created our client and have provided all the details of our request, its time to decide what the app must do when the server sends its response. This part is handled by the HTTPClient’s onload() function.

xhr.onload = function()
{
try
{
//handle server response here
}catch(E)
{
alert(E);
}
};

Because we cannot be certain beforehand that the server will respond in exactly the way we expect or that our handling of its response data will be perfectly error-proof, a try-catch is important here.

As mentioned earlier, the data sent by the server can be of two forms- xml format or just simple text. Titanium also provides us a third option of dealing with the response – in binary form. Hence, we can use responseText (normal text or JSON reply), responseXML(XML reply) or responseData (binary reply) depending on the type of reply. You can include a simple if-else-if block to check the response format within your app itself (if you’re in real rush, make a quick and dirty check by simply using alerts within the if-else-if once and run before you type in the rest of the processing code). The NY times returns data in xml so within the try we use the following code.

//get the overall xml document
var doc = this.responseXML.documentElement;

//this gives us an array of all the ‘item’ tags in the document
var items = doc.getElementsByTagName(“item”);

//get the title of the page
var doctitle = doc.evaluate(“//channel/title/text()”).item(0).nodeValue;

var x = 0;

We will now loop over the array of ‘items’ to fill each row of the feed table to display.

for (var c=0;c<items.length;c++)
{
//get the cth feed item from the array
var item = items.item(c);

//get the title of the feed item
var title = item.getElementsByTagName(“title”).item(0).text;

//create a new row and a label field in it to hold the title
var row = Ti.UI.createTableViewRow({height:80});

var label = Ti.UI.createLabel({
text:title,
left:72,
top:5,
bottom:5,
right:5,
color:’#000′,
textAlign: ‘center’,
});

row.add(label);

//set the url to go to when user selects the row
row.url = item.getElementsByTagName(“link”).item(0).text;

//add this row to the data object
data[x++] = row;

}

Now that we have filled each row and added it to the data object for the TableView, we will create the TableView itself and attach an event listener to it. Don’t forget to add the TableView to a window!

var tableview = Titanium.UI.createTableView({data:data});
tableview.addEventListener(‘click’,function(e)
{
//create a new Window
var w = Ti.UI.createWindow({title:doctitle});

//create a new WebView that shows the url attached to the row clicked
var wb = Ti.UI.createWebView({url: e.row.url});

w.add(wb);
w.open({modal:true});
});

//Open a new window to show the feed table
var window = Ti.UI.createWindow();

window.add(tableview);
window.open();

Now our try block is finished and all we have to is send the XML HTTP Request. Remember, this is outside the onload() function. That’s kinda obvious, but who knows!

xhr.send();

And with that our very own custom feed reader is ready! If you wish to make a similar app for another webpage, be sure to view the source code for the page first. This is because not all pages are formatted the same way and all the tags can vary. But do try to experiment…there are as many things we can do as there are types of feeds- picture feeds, video feeds and even radio feeds. So have fun coding!ūüėÄ

P.S.: You can find the app.js file of this project here.

 

/** Moving from Android Apps to BlackBerry Development*/

When I started messing with BB apps, I was quite comfortable with Android development. Seeing as they both use the Eclipse environment, I happily assumed that the transition from Android to BlackBerry would be no biggie. But boy, was I wrong. A learning curve is just that, a curve. There’s ups and there’s downs. So below I’ve listed out some of the greater differences between Android and BlackBerry that have made my developer life both better and worse. I hope that this helps some other kindred soul about to make the jump from Android dev to BlackBerry dev.

  1. XML…WHAT’S THAT?

    I don’t know why, but for some reason, the near absence of xml in every single sample BlackBerry project I’ve seen makes me squirm. I mean, xml makes things that much more easier people!

  2. CLEANER RESULTS

    Personally, I feel that for all the depth of functionality Android provides, their visual output is, well, sorta “kiddish”. I mean, just check out all the Android icons…a wee bit cartoonish, if you ask me. Which is why, when I was recently working on a BlackBerry app that involves drawing graphs and piecharts, I was pleasantly surprised by their polished look and feel.

  3. BUTTONS AND MENU-ITEMS

    The folks at RIM don’t seem to like buttons much. The BlackBerry Developer docs state that using buttons is not a very good idea and it’s better to make use of the application menu. Interesting.

  4. FLOW OF EXECUTION

    I love Android for the clear structure of the programs. One activity at a time. Simple. BlackBerry is another story. There’s Screens(yes, one at a time) but there’s just something about the other classes (especially UiApplication) that continues to muddle my chain of thoughts. But then again, this might not even have anything to do with the classes…maybe I just haven’t got a hang of them yet.

/** Simple Database on SDCard */

Ok, so for our first app, we’re going to ditch the tried and tested ‘HelloWorld’ and go for something new – a simple app that creates a database and then plays with it.

To create a database, we need an SDCard to store it in. So first off, create a new folder titled BBCard (or whatever the heck you wanna call it!ūüėČ ). This folder can be anywhere in your system…the local disk or desktop or whichever place pleases you. For the sake of consistency, I put mine within the workspace folder.

Once you have an SDCard ready, you can create a simple database. Our database is going to contain only one table. Let’s call it EmployeesTable. This table has three fields – one each for employee name, employee id and employee salary.

Open up MyApp.java and fill the following code into the constructor :

// Create a string holding path to DB directory
// The path to your SDCard file is always /SDCard/
// But I have added subfolders for the sake of clarity
// As you will see later, if the subfolders dont exist
// they will automatically be created
String dbLocation = "/SDCard/Databases/Revenues/";
// Create URI;this is th complete path to the DB file called Employees (this our DB's name)
uri = URI.create(dbLocation + "Employees"); // Create a new DatabaseOptions object forcing foreign
// key
// constraints
databaseOptions = new DatabaseOptions();
databaseOptions.set("foreign_key_constraints", "on");

// Open or create a plain text database. This will
// create the
// directory and file defined by the URI (if they do not
// already
// exist).
db = DatabaseFactory.openOrCreate(uri,
new DatabaseSecurityOptions(false));
// Close the database in case it is blank and we need to
// write
// to the file
db.close();

Now we have created a file to store our database. If you run only this code on the simulator, a file called Employees will be created within the SDCard folder. After running the app, you can go to the folder and see for yourself. The neaxt thing we need is a way to enter and read data from our DB. The best way to do this is to have a ‘database manager’. Basically this is a class that will do all the talking to the database for us.
So within the package explorer in Eclipse, go to YOURAPP -> src -> mypackage and right click on mypackage. Now go to new -> class. We are going to make a DBManager class. Type in DBManager as the class name and click Finish. Now create a constructor and two functions- one to read and one to write – within this class as follows:


/**
* A class to handle SQLite database logic
*/
public class DBManager
{
private Database _db;

/**
* Constructs a new SQLManager object
* @param db Database to manage
*/
public DBManager(Database db)
{
_db = db;
}

//**************************************************
//...................INSERTION......................
//**************************************************

/**
* Adds an Employee row to the EmployeesTable table in the database
* @return The id of the new directory Revenue
*/
int addEmployee(int id, String name, float salary)
{
long id2 =-1;


// Insert a new record in the table
// 1. Create a statement to execute
// 2. Prepare statement for execution
// 3. Bind argument values to ? marks in statement. Binding is done to improve performance.
// 4. Execute
// 5. Close the statement
Statement statement = _db.createStatement("INSERT INTO EmployeesTable VALUES( ?, ?, ?)");
statement.prepare();
statement.bind(1, id);
statement.bind(2, name);
statement.bind(3, salary);
statement.execute();
statement.close();

// Retrieve the auto-generated ID of the Revenue just added
id2 = _db.lastInsertedRowID();

return (int)id2;
}

/**
* Retrieves all records in the Revenues database table
*/

Cursor getRevenues()
{

Cursor cursor = null;

Statement statement = _db.createStatement("SELECT * FROM Revenues");
statement.prepare();
cursor = statement.getCursor();

return cursor;
}
}

Okay now that we have a database and a manager class,it’s time to create our table. Go back to MyApp and create a function within that class called initializeDB(). This will be our function where we create a table and add data using DBManager. Fill the function as shown :

/**
* function to create table and enter data
*
* @param uri
* Path to DB file
* @param databaseOptions
* DB options
*/
public void initializeDB(URI uri, DatabaseOptions databaseOptions) {

Database db;

//Open the database.
db = DatabaseFactory.open(uri, databaseOptions);

//Create table statement.
Statement statement = db
.createStatement("Create table if not exists Revenues ( _id INTEGER NOT NULL, _geolocation TEXT NOT NULL, _serviceLine TEXT NOT NULL, _amount float NOT NULL, PRIMARY KEY (_geolocation,_serviceLine) )");
statement.prepare();
statement.execute();
statement.close();

// Create a new manager to talk to our database db.
DBManager manager = new DBManager(db);
//Add four new rows.
manager.addEmployee(1, "Samantha Adams", 12000.00);
manager.addEmployee(2, "Sameer Sinha", 10000.00);
manager.addEmployee(3, "L. V. Jones", "BPO", 12000.00);
manager.addEmplyee(4, "Alice MacMohan", 9000.00);
Dialog.alert("4 rows added.");

db.close();

}

Don’t worry too much about missing try-catch blocks. Eclipse will automatically prompt you about these and add them where required. We’re nearly there! All we have to do is call this function from the MyApp constructor and then read the table.

initializeDB();
DBManager manager = new DBManager(db);
Cursor cursor = null;

while (cursor.next()) {
Row row = cursor.getRow();
String s = ‚ÄúEmployee‚ÄĚ+
String.valueof(row.getFloat
(0))+row.getString(1)+‚ÄĚearns $‚ÄĚ
+String.valueof(row.getFloat (2));

Dialog.alert(s);
}

Yes,yes, you can now run the app!ūüėÄ

NOTE: Be sure to call the initializeDB() function ONLY ONCE when you run the app. After running the app once and seeing the dialog that confirms the addition of new rows, delete the line that call this method in the MyApp constructor and rerun the app. Otherwise, your app will crash because of constraints on the table.

Databases in BB are very versatile and a lot more can be done with them but I have included only very basic insert and read operations to keep things simple. This has been a very long post but I hope you find it useful.
Happy Coding, my lovelies!ūüėÄ

Follow

Get every new post delivered to your Inbox.