Posterous theme by Cory Watilo

Filed under: tutorial

Twitter Tabbar Indicator Added to Universal iOS Template

Today I pushed a nice little update to the Tabbar Support branch of my iOS-Universal App Template project on Github.  I added in the "Twitter tabbar slider" indicator.  Though it isn't that flashy it was the attention to detail that made Tweetie so popular and usable when it first came.  While it has since been duplicated I found it interesting that most examples don't have support for landscape orientation nor for iPads.  After looking through @boctor's code on idevrecipes.com I figured I would be able to drop the code in for my template within a few hours.

If it seems too good to be true then it usually is.  I realized why I didn't see a whole lot of support for the indicators in other orientations or for the iPad.  The first obstacle was orientation support.  In @boctor's code the indicator is added as a subview to the main window.  This is not a bad practice because it ensures that the indicator is always on top of any subviews within the app. Unfortunately UIWindow doesn't support orientation, so when the device rotates the image looks crooked.  The solution is to add the indicator to the tabBarController's view.  Now that the image is repositioning itself with the orientation, unfortunately the new position is not centered.  To ensure that you will position the indicator in the center of each tabbar item ,regardless of orientation, you have to use the following calculation:

The last piece to the puzzle was to be able to force the indicator to recalculate it's position based upon the orientation.  This wouldn't be an issue with UIViewController, but I don't want to add in boilerplate code for each VC that I have.  (I already have boilerplate that I am going to abstract out with the next update).  Using NSNotification or a custom protocol seemed like overkill…and it was.  I ended up creating a category for the UITabBarController that overrides:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration

and calls the delegate method for the tabbar that is selected.

The rotation animation on the splitviewcontroller seems a little sluggish so I need to track that down and I am hoping to take out the dependency for an image and draw it programmatically.

A BIG SHOUT OUT to Peter Boctor (http://idevrecipes.com/) and Loren Brichter for being innovative and providing the code that was the basis for my little addition.

Please Enter Your Password Gesture

The more and more that I develop apps the more I try to challenge myself to come with creative ways for users to use the apps. Really trying exploit the power of multi-touch. As mentioned in a previous post, this trend is becoming more and more mainstream. Unfortunately, when it comes to authentication, we are still stuck using the old attage of a PIN and/or using biometrics, which never really caught on with the masses. I personally think that has to do with implementation of it not the mechanism.

In order to try and contribute, to a hopefully better way to authenticate, I started working on a password gesture framework. Though password gestures aren't new what I think differentiates mine, at least conceptually, is how it deals with resetting it. My first thought was to just stick with the same old "email me my password", however email isn't always relaible and the "gesture" password isn't stored on a server, but on the device. In addition, I didn't want to have to rely on a separate server or component. Lastly, by doing that I am relying on an outdated "desktop" thought process of handling lost/forgotten passwords. So how do I give a user a usable and easy way to reset their password without having a server dependency or leaving the app?

My solution is that during the password setting process is to present the user a list of pictures and have them choose N out of X. If they need to reset their password they will be presented with the "reset" picture screen and select the correct ones. If the correct set of pictures are choosen then reset occurs. If not then fail. Due to my extremely busy schedule I haven't had the opportunity to really dedicate the time I want to. I am hoping that posting this to github that the iOS community will take it and make suggestions or fork and implement it with ideas and features that I haven't thought of.

I have started the project as a sample app, but once it reaches a stable point I will make it a static library that can be dropped into any project.

It goes without saying that I am really looking for feedback on this. All comments and suggestions are welcome.

Password Gestures on Github

(download)

Using CAAnimationGroup for View Animations

Lately I have been pushing myself to increase my knowledge and understanding of more advanced animation techniques. The more that I
dig into the lower level
core graphics framework and core animation the more impressed I become with their power. I also have a greater 
respect for those developers who can leverage their power in creative ways.

For most use cases leveraging uiview basic animations with blocks will do exactly what you need. However, in my particular case I wanted to
accomplish the following. Scale, rotate and change center point of subview "A" to subview "B" all at the same time.

Taking my own advise I first started down the path of using basic uiview animations. I want to make sure that each different piece of
the animation would perform the way I wanted them to. Separately, they did exactly what I wanted. Unfortunately, grouping these together was
not going to happen with uiview animations.

When I ran the process all the animations executed, but the transition to subview b's center point was very jerky. To make sure that I didn't
miscalculate any of the individual animations I went back and tested each one separately. Each animation ran smoothly. When I ran the group within the block
I had the jerkiness problem of animation the center point.

After going back and reviewing Apple documentation I found what my problem was. Imagine that. To do the rotation I apply a transform on
the view's layer. However, the transform performs it's animation based upon the views center point. Since I was trying to apply an
animation on the center point as well the group animation had to reposition subview A's center point first before it could apply any of
the other animations. Hence the jerkiness.

I pushed all my animations to a CAAnimationGroup and all the transitions were performed.


-- 
Cory D. Wiles
kwylez@gmail.com
www.corywiles.com | twitter.com/kwylez

Custom UIActionSheet Using Core Animation

About four months I posted a blog and project that showed how to customize the buttons of a UIActionSheet.  In the disclaimer I stated that because of the use of the private api's if you attempted to submit your app with this technique to the App Store it will get rejected.

This time around a created a simple, yet effective customized, mock UIActionSheet.  Essentially it is just a custom UIView with three buttons that animates and dismisses just let an UIActionSheet.  All you have to do is assign a method to each of the buttons.

If I have time then I'll try and make it even more extensible by creating a custom delegate to make the classes even more reusable.

Upcoming to Universal iOS App on GitHub

(download)

In anticipation for the upcoming public release of iOS 4.2, I have updated my Universal iOS App project (iAd Branch).  The project will run on 3.2 and up with iAd support for iPhone and iPad (4.2 only for iPad).

I ran into some interesting hurdles while working on this update.  The first of which is that adding in iAd support for a project using a UISplitViewController SUCKS! #FAIL When iAds where first offered in the 4.0 iOS they came in two different size: 320 x 50 (ADBannerContentSizeIdentifier320x50) and 480 x 32 (ADBannerContentSizeIdentifier480x32) which served their purpose since you could use iAds only on the phone.  When iAd support was added for the iPad Apple was smart and deprecated those properties and added ADBannerContentSizeIdentifierPortrait and ADBannerContentSizeIdentifierLandscape, thus abstracting the dimensions that are available for any current and future devices.  This unification works great on the iPhone and iPad...except for when you implement UISplitViewController on the iPad.  The reason being that even though your root view or "detail" view controller are in landscape or portrait mode their widths aren't in the expected frame width for either choose of iAd. Thus you get an inaccurate display and you will an error in:

- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error

stating that an ad has displayed but is being obscured. In order to get around this I had to add in some padding to readjust the 'y' coordinate for the tableview's frame (only when the ad appears).  Why the rotation, and only on the iPad, gets screwed up I am not sure at the moment.  I created a simple, iPad only project and got the same results so there might be a bug, but until I am able to verify, my "padding" works".

It is important that if you clone/run this project that you read the debug console for iad display errors.  These are relevant errors passed to the delegate method and don't have to do with my code.  You will notice in the video that ad fails to load the first round.  This is due to an error from Apple serving up the ad because inventory is not available. Second time is the charm.

*important - always implement delegates to handle failures

In the next few weeks I'll be adding a branch where the Universal app will have Tabbar support.

CWCustomAccessoryView - Custom UITableViewCell AccessoryView

Around the same time that Oliver Drobnik (Formely Dr. Touch) published his blog entry, Custom-Colored Disclosure Indicators, I was also in the middle a client's project where the table view cells each had a different colored uitablviewcellaccessory.  I had to deal with 20 different images for the accessory views (10 for pre-iPhone4 and 10 for retina display).   At the time I knew having to manage the images themselves and the code to display those views was unwieldy and cumbersome.  I took inspiration from Oliver's post to come up with a class, CWCustomAccessoryView, which allows the developer to customize the way the accessoryView for a cell looks which includes the stroke, _>_, and fill color.


Though the code is almost a month old and I haven't had that much time on improving it, but after reading Ray Wenderlich's blog on Arc's and Paths I see I need to make the accessory view look for like Apple's detail disclosure button to make everything look really polished.

Per usual the code is hosted over at GitHub.  Comments and improvements are ALWAYS welcomed.

Customizing UIActionSheet Buttons

One of the great benefits of iOS development is that Apple has provided the ability to customize almost any element thus not limiting a designer or developer with a stock look and feel.  Just take a look at subtle examples in Twitter for iPhone to the extreme of the Outside Weather app or Starbucks.  I am working on a nice size project and one of the requirements is to have the UIActionSheet buttons be a different color than the default gray color.  This turned out the be as straightforward as trying to change the look and feel of a tabbar.

::NOTE TO APPLE:: Customizing Tabbars and UIActionSheet buttons should be a lot easier. ::END NOTE::

It took a few hours, but I finally knocked it out.  At first glance I figured that each one of the buttons would be an instance of UIButton and I could located them in the view hierarchy and just update the background color either in a delegate method or subclass UIActionSheet and override drawRect:.  NEGATIVE.  

My next possible approach was to create my own custom view(s) and slap them on the UIActionSheet's main view and send everything else to the back.  Granted that has worked for some people and is a totally viable option, but I found it to be a very hacky solution for what I was doing.

After looking up a few questions on StackOverflow it turns out that sometime after iOS 3.1 the subviews in the UIActionSheet are an undocumented class instances of UIThreePartButton.

::BIG DISCLAIMER - YOUR APP WILL PROBABLY GET REJECTED IF YOU SUBMIT WITH THIS TECHNIQUE::

After digging up that little nugget about UIThreePartButton I finally had turned a corner.  The next hurdle was trying to find the correct method to use from the UIThreePartButton class to change the background color.  Unfortunately, there isn't a backgroundColor property for that.  Granted since I am dealing with a class that inherits form UIView I could set the subviews backgroundColor property to [UIColor redColor], but when I did that I didn't get the expected result of a button with a red background.  The button became a red tint and the view behind the button was red as well.  Obstacle.  Looking at the methods/properties that I DID have I went on a little intuition that Apple wasn't using a color, but a stretchable background image for the button.  I grabbed the background graphic that I wanted and used - (void) setBackgroundImage:.  SUCCESS!!!!!!!

I wasn't quite finished.  Background button was what I wanted, but I needed to change the font color from black to white.  But wait there isn't a method to set the font. However, UIPushButton inherits from UIThreePartButton so once again going on an educated guess/intution I was able to use setTitleColor:forState: and perfection.  Excatly what I wanted and needed.  UIActionSheet with red buttons and white font.

Even though I can't submit any app to the AppStore because of the undocumented class working through the exercise was very enlightening in the areas of ui customization, design patterns and general problem solving skills which should always be in the top of a developer's skillset.

I posted my example on github.  It was compiled with 4.0 with XCode 4 Preview 3, but XCode 3.x should work.  If you run into any problems then let me know.

Creating a Universal iOS App Tutorial

Just when I thought I had a somewhat decent grasp on developing and deploying iOS apps Apple came out with the iPad and threw a whole new element in the mix when it comes to developing.  Thankfully, the iPad will allow iPhone apps to run on the device, but the user experience is definitely sub-par.  So what is the best approach to providing an native iPhone app and a native iPad app?  The first option is to duplicate your existing iPhone app code base and modify all your views and some of the controllers to take advantage of the features in the 3.2 SDK.  The problem with that is the massive DUPLICATION of code and to be honest it seems quite lazy.  I have seen lots of examples where developers use the idiom check for which device is being used, as well as, runtime checks for selectors in order to leverage the correct methods/classes for the given device.  While this is certainly a better approach then having two separate code bases with 90% of the same code you now have code that is sprinkled/littered with if/else checks.  Unfortunately, you are once again stuck with code that will be maintainable for long.  After reading the chapter on universal apps from the upcoming book from Pragmatic Programmers, iPad Programming, I found a much better design pattern of splitting out the app into Shared, iPhone and iPad resources, classes and delegates.

As a side note, due to the ever exponential growth of iOS device popularity developers are not going to have the bonus of just jumping straight into writing an app like we did when there was just the iPhone.  A lot more thought needs to be given to design patterns (especially regards to the quality of your MVC) and application flow.

In order to make life a little easier on myself since a few universal apps are coming in my near future I decided to create a basic "template" for a universal app.

Features
  • Compiled for 3.2 and 4.0
  • Utilizes navigation controller based app for iPhone device and SplitViewController for iPad
  • Shared "model" class and controller classes
  • Separate resources (classes/xibs) for the different devices

Comments and improvements are ALWAYS welcome.  One improvement that I know I want to make is having the "detail" controller from the SplitViewController to be a UINavigationController.

(download)

How to Create SMS Ballon iPhone Table View

I was working on incorporating an "sms ballon" type view for a client and while doing some research on the best, and different, ways to implement the functionality I came across a great tutorial, but thought it could be cleaned up just a little bit which should make your FPS increase and I fixed some memory leaks.  I wasn't able to run any performance tests on it so I would welcome ANY feedback how to improve the code.

The key to making the "ballon" background grow and shrink based upon the amount of text is using:

UIImage *balloon = [[UIImage imageNamed:self.imgName] stretchableImageWithLeftCapWidth:24 topCapHeight:15];

If someone has any advice on how to make the font look better please let me know.

Displaying Data on the iPhone with Index UITableView

It is forgone conclusion that if you need to present a large amount of data with a UITableView then you should do so using an index and index sections.  As with most tutorials that I have read on this topic, the scenarios used got me 80% of the way.  In my humble opinion, the solutions where either over engineered or they didn't apply to my use case.  Hopefully this tutorial/sample project will bridge the gap.

The tutorial that I got the most from is: iPhone Development: Creating Native Contacts like screen.

One of the biggest hurdles that I had to over come, that was different from the contacts tutorial, was that I wasn't using a database and therefore didn't have a predefined sub-result set for each character.  I was having to do the opposite.  I had to iterate over my result set, array of states, grab the first letter from each item, check to see if there was already a dictionary key that existed for that letter and proceed accordingly.

Logic Flow
Iterate over states
Get the first letter of that particular state
Check to see if there is a key in the objectsForCharacter dictionary
   - YES: add the state string to the arrayOfNames array and then set the arrayOfNames to the objectsForCharacter dictionary for the appropriate key
  -  NO: remove all objects from the arrayOfNames array and add the firstLetter to the arrayOfCharacters.  Then proceed on to the above "YES" steps
Once all the states have been "proceed" then reload the table data

Final Model
Though it sounds some what complicated with all the arrays, dictionarys, etc. once you break it down to a visual model then the code is easier to comprehend.

[[objectsForCharacters objectForKey:@"A"] objectAtIndex:0]; // Alabama
[[objectsForCharacters objectForKey:@"A"] objectAtIndex:1]; // Alaska
[[objectsForCharacters objectForKey:@"A"] objectAtIndex:2]; // Arizona
[[objectsForCharacters objectForKey:@"A"] objectAtIndex:3]; // Arkansas

Download Example Project (comments/enhancements are welcomed)
IndexedTable.zip