Posts tagged OSS
Posts tagged OSS
4 notes &
Facebook’s recent attempt to “revert” its official iOS client from HTML5 to a native iOS app seems to have been very well received (well, at least by the iOS community, not sure how the HTML folks think). The new app is now much faster and reliable than before, and although this update is primarily an engineering rework, it does come with a few really nice UI/UX improvements, and the floating header in the home view is one of them.
The following is a screenshot that shows how the new header looks like when it shows:

As we can see from the above screenshot, the header contains three buttons: Status, Photo and Check In. The interesting thing with this header is its location changes as the underlying table (an UITableView, or to be specific, a subclass of UIScrollView) scrolls. When the underlying table first shows, the header floats right on top of the table. When user scrolls up and down, the header shows and hides itself in an elegant way, which both makes way for an optimal screen space for viewing table contents when needed, and allows easy access to the buttons that it contains. What a smart design! How can we implement this in Objective-C?
Feeling inspired, I sat down and started to “decode” the header in my head. About one hour later, DYFloatingHeaderView was created.
Like other open source iOS controls that I created, DYFloatingHeaderView is very simply to integrate:
[Updated Sep. 18th, 2012] As Sun Long pointed out in his comment, there is a flaw in the original design that by setting scrollView.delegate to an instance of DYFloatingHeaderView, the original delegate will no longer be accessed. The new version has this issue fixed, although it needs a few more steps to integrate, as I’ll outline below.
Step 1: Download the source from Github, unzip, copy and include DYFloatingHeaderView.m and DYFloatingHeaderView.h into your project
Step 2: Since technically the header is not a subview of the table view (otherwise it will scroll together with the table, which makes it very hard if not impossible to maintain its own position), we cannot simply create and reference DYFloatingHeaderView within an UITableViewController. Instead, what we need to do is to make the header a sibling of the table. In order to do this, all we need to do is to create a class (if it doesn’t exist yet) that serves as a container view for both the header and the table. e.g. In Xcode, create a new UIViewController subclass HomeViewController, and add the following lines of code in viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
// Floating header
DYFloatingHeaderView *floatingHeader = [[DYFloatingHeaderView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, [DYFloatingHeaderView height])];
[self.view addSubview:floatingHeader];
// Table view
self.listViewController = [[SampleListViewController alloc] init];
self.listViewController.view.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);
self.listViewController.headerView = floatingHeader;
[self.view insertSubview:self.listViewController.view belowSubview:floatingHeader];
}
Step 3: In SampleListViewController, declare a DYFloatingHeaderView property, and update scrollView’s insets (this is needed to allow the scrollView to display contents without being blocked by the header):
// In SampleListViewController.h
@property(nonatomic, strong) DYFloatingHeaderView *headerView;
And then in SampleListViewController.m:
@synthesize headerView = _headerView;
- (void)setHeaderView:(DYFloatingHeaderView *)headerView {
_headerView = headerView;
[_headerView updateScrollViewInsets:(UIScrollView *) self.view];
}
Step 4: Still in SampleListViewController, override the following methods defined in UIScrollViewDelegate, and call the corresponding DYFloatingHeaderView method in each:
// In SampleListViewController.m
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
[self.headerView scrollViewDidScroll:scrollView];
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
[self.headerView scrollViewWillBeginDragging:scrollView];
}
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
[self.headerView scrollViewWillBeginDecelerating:scrollView];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
[self.headerView scrollViewDidEndDecelerating:scrollView];
}
There you should have it!
The following is a very short YouTube video that I made to demonstrate how DYFloatingHeaderView works in action!
As always, you are welcome to leave a comment below if you have any questions or suggestions. I’d love to know if you use it in your own projects. If you like DYFloatingHeaderView or any other open source components that I created, please consider following me on Twitter. :)
Tweet4 notes &
Up until about a year ago, iOS developers could still create their killer apps happily by hooking up a few UITableViews with a standard UINavigationController and/or UITabBarController, and put their favorite stuff in.
But things have changed. Nowadays, iOS developers and designers are making every effort to tweak the standard iOS controls (oh the mighty iOS HIG!) to produce user experiences that are more natural and visually appealing. Refresh buttons are now replaced by a pull-to-release gesture, tappable areas are becoming smaller (which is not always great), alerts are not getting in the way, unnecessary navigation controls are removed altogether for a chromeless experience…
Yes, it’s this chromeless thing that keeps me excited. As I mentioned in a previous post, I love the way how the author of Logos Quiz designed its navigation that only very few navigation controls (a button to navigate to a different view, and a custom back button to navigate back) are left on screen. There is also an app called Backboard, which has taken chromeless to an extreme by dropping out on-screen navigation controls completely. There is no navigation bar, there is no tab bar. The entire screen is reserved to the app, and one just needs to swipe here and there to navigate around. What a simple yet natural experience!

As I said previously, I’m such a curious person that when I see something beautiful I really want to figure out how it’s made (no, I don’t mean Mona Lisa), and in this context it’s the gesture based navigation that draws my attention. So I sit down and hacked on my Mac for a few hours, and then I came up with my solution: DYNavigationController.
With DYNavigationController, you can easily create chromeless iOS apps that are purely or partially gesture based. There are just a few steps to follow if you want to use it in your own project.
Step 1: Download the source code from github and copy two files (DYNavigationController.h and DYNavigationController.m) to your project.
Step 2: In your appDelegate (or wherever that fits your situation), import DYNavigationController.h, create an instance of DYNavigationController, and give it a rootViewController, which is your main view controller (I’m NOT using ARC here in this example):
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
RootViewController *rootViewController = [[[RootViewController alloc] init] autorelease];
DYNavigationController *navigationController = [[[DYNavigationController alloc] initWithRootViewController:rootViewController] autorelease];
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;
}
Step 3: In your root controller, there are two ways that you can do to push a new view controller onto your current view stack. (This is similar to pushViewController: animated: in UIViewController). First of all, you need to implement a protocol called DYNavigationControllerDelegate in your root controller’s header:
@interface RootViewController : UIViewController <DYNavigationControllerDelegate>
And then, if you want your user to navigate to a new view by tapping on a button or a table view cell, you can implement an optional property navigator in your root controller; or if you just want your user to swipe from right to left on the screen to go to the next view, you can simply override an optional method called viewControllerToPush. I’ll explain the two approaches here one by one. You can choose whether you want to go with step 3A or 3B.
Step 3A: Tap to navigate. Implement the navigator property like this:
@implementation RootViewController
@synthesize navigator = _navigator;
and then in the place where you want to push a new view controller (e.g. in a button handler) call pushViewController on navigator:
- (void)nextButtonTapped {
DetailViewController *detailViewController = [[[DetailViewController alloc] init] autorelease];
[self.navigator pushViewController:detailViewController];
}
Step 3B: Swipe to navigate. Override the following method in your root controller:
- (UIViewController *)viewControllerToPush {
return [[[DetailViewController alloc] init] autorelease];
}
This tells DYNavigationController which view controller to push to the current view stack, and DYNavigationController will take care of the rest.
Your user can navigate back anytime by swiping from left to right.
Please note that, if you don’t want your user to navigate to a new view from root controller or any view controller in your app, you don’t need to do any of the things mentioned in step3. DYNavigationController automatically takes care of everything that is necessary to display your view and navigate back.
There you have it. I hope this makes it easy for you to write your next chromeless iOS app. I’ll definitely consider designing my next iOS app to be as chromeless as possible (if that makes sense).
As always, if you have any questions, please don’t hesitate to contact me by leaving a comment below or following me on Twitter. If you use DYNavigationController in any of your projects, I’d love to hear. :)
Enjoy!
I’m very pleased to find out that DYNavigationController is selected as Control of the Week by CocoaControls.com. You can find out more about it here. They’ve even made a short video showing DYNavigationController in action! Many thanks to the Cocoa Controls folks! :)
Tweet2 notes &
When I worked on the latest update of my iOS app Veggie in China, I needed a way to enable my users to rate restaurants. I wanted to have a rating view which displays five stars, and that user can tap on any of the stars to rate.
I googled a bit and found this tutorial written by Ray Wenderlich. It worked great. However, there were a few things that I really needed missing from that tutorial:
Based on these ideas, and since imitation is the greatest form of flattery (thanks Ray!), I decided to create my own one. So DYRateView was born. :)
This is how it’s used in Veggie in China:


It’s very simple to use DYRateView in your project. All you need to do is to download the source code from Github, and add the following two files to your project:
I’ve also made a few images myself for the stars. You are welcome to use them if you don’t want to create your own ones. Just drag them from the Resources folder into your project and make sure the files are copied over.
When you are done adding DYRateView to your project, you can start using it. The following shows an example:
DYRateView *rateView = [[[DYRateView alloc] initWithFrame:CGRectMake(x, y, 100, 14)] autorelease];
rateView.rate = 4.7;
rateView.alignment = RateViewAlignmentRight;
[self.view addSubview:rateView];
You can make it editable:
rateView.editable = YES;
and then hook it up to a delegate in order to receive updated rate whenever user makes a change:
rateView.delegate = self;
// ….
#pragma mark - DYRateViewDelegate
- (void)changedToNewRate:(NSNumber *)rate {
self.rateLabel.text = [NSString stringWithFormat:@"Rate: %d", rate.intValue];
}
I’ve added a sample project in Github to demonstrate its usage:

That’s it. I’ll be more than happy if you find DYRateView useful. Feel free to let me know any code related issues on Github or in the comments below.
Enjoy!
Tweet