Thursday, October 21, 2010

Sizing a launcher item image in Three20

Recently I got deeper into iPhone (or iOS) programming, doing some projects for fun and for fee.
My friend Reuven wanted me to use a framework called Three20 in the context of a project I am doing for XMPie, but the person who really pushed me into it is Yosi Taguri of who gave me a crash course on Three20.
So, I am working now on converting the XMPie project to Three20, and I spent the last couple of hours on trying to get the launcher view work with some images that are of unknown sizes. I initially thought I will have to sub-class the launcher view and all its related classes (TTLauncherItem, TTLauncherButton), but this is of course the wrong way of doing things in Three20...
There is a better way which is to use the stylesheet mechansim of Three20. I read the tutorial by Matt Vague (Three20 stylesheets tutorial), but it was not enough to get what I wanted.
What really helped me figure this one out is a tool named TTStyleBuilder by a guy named Keith Lazuka.
finally I was able to create the following style in my stylesheet to get the images to behave:

- (TTStyle*)launcherButtonXM:(UIControlState)state {
    [TTPartStyle styleWithName:@"image" style: TTSTYLESTATE(launcherButtonImageXM:, state) next:
     [TTTextStyle styleWithFont:[UIFont boldSystemFontOfSize:11] color:RGBCOLOR(180, 180,180)
                minimumFontSize:11 shadowColor:nil shadowOffset:CGSizeZero
                  textAlignment:UITextAlignmentCenter verticalAlignment:UIControlContentVerticalAlignmentBottom
                  lineBreakMode:UILineBreakModeClip numberOfLines:1 next:nil]];

// Our launcher button image style
- (TTStyle*)launcherButtonImageXM:(UIControlState)state {

    TTStyle* style =
     [TTShapeStyle styleWithShape:[TTRoundedRectangleShape
                                   shapeWithRadius:8] next:
      [TTBoxStyle styleWithMargin:UIEdgeInsetsMake(0, 0, 0, 0)
                          padding:UIEdgeInsetsMake(22, 22, 22, 22)
                          minSize:CGSizeMake(0, 0)
                         position:TTPositionStatic next:
          [TTImageStyle styleWithImageURL:nil defaultImage:nil contentMode:UIViewContentModeScaleAspectFit
                                     size:CGSizeMake(57, 57) next:nil

    if (state == UIControlStateHighlighted || state == UIControlStateSelected) {
        [style addStyle:
         [TTBlendStyle styleWithBlend:kCGBlendModeSourceAtop next:
          [TTSolidFillStyle styleWithColor:RGBACOLOR(0,0,0,0.5) next:nil]]];
    return style;

You use this style in the launcher by setting the style property of the launcher item: = @"launcherButtonXM:";
        [_launcherView addItem:launcherItem animated:YES];

Three20 is cool!

[Edit] Based on some questions I got, I want to clarify that the style methods above are placed in my XMDefaultStyleSheet which is defined as an inherited class of TTDefaultStyleSheet. I create an instance of this class and set it as the default style sheet in the App Delegate applicationDidFinishLaunching method like that:

    // register our stylesheet
    [TTStyleSheet setGlobalStyleSheet:[[[XMPDefaultStylesheet alloc] init] autorelease]];