Archive for November, 2011

 

Sliding clocks around the screen a la Path

 
 

The new Path app has hit the App Store, and the updated UI is GORGEOUS.   I was quite intrigued by the little touches, particularly the little clock icon that slides up and down the right-hand side of the screen as you scroll down the timeline. It looks really neat, and it got me wondering how it was done.

Turns out, it’s actually not that difficult (although it’s still a lovely UI touch even so).

The main view in Path is a heavily-customised UITableView sat inside a UINavigationController (although the UINavigationController bit is irrelevant at the moment). UITableViews are themselves heavily-customised subclasses of UIScrollView, which means that all the goodies that a UIScrollView provides are available to instances of UITableView.

There’s one particular goodie that’s relevant here. This is UIScrollView's contentOffset property, which shows how far from the origin the scrollView – or in this case, our tableView – has been scrolled. When the table’s at the top, the contentOffset's y value will be zero – but if you had a table that was (say) 1000 pixels high, that contentOffset would gradually increase until at the very bottom of the table it had a y value of 1000 pixels.

Another property that’s relevant here is the tableView’s contentSize property. If you access that after the table has finished loading – ie in the viewDidAppear method – then this will return the total height of the table with all rows fully-populated.

- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
 
maxTableHeight = self.tableView.contentSize.height;
frameTableHeight = self.tableView.frame.size.height;
workingTableHeight = maxTableHeight - frameTableHeight - 64;
 
NSLog(@"TableView maxTableHeight = %f", maxTableHeight);
NSLog(@"TableView frameTableHeight = %f", frameTableHeight);
NSLog(@"TableView workingTableHeight = %f", workingTableHeight);
 
}

Dividing the contentOffset.y value by the contentSize.height will give you how far down the tableView things have scrolled as a percentage value. When the table first loads, the contentOffset.y value will be zero, therefore we’d be 0% down the table. At the bottom, we’d be 100% of the way – and obviously varying percentages along the way.

The third value that will help out here is the height of the table’s frame – in other words, how much of the overall screen the tableView occupies. If you’ve got a status bar and a navigation bar, that’s the full height of an iPhone screen – 480 pixels – less 20 pixels for the status bar and 44 pixels for the navigation bar – a total frame height of 416 pixels.

Now imagine that you created a UIView of some description, and “floated” it as the front-most view so that it appeared on the right-hand edge of the screen. (If it’s a subView of the main window, then the origin remains constant and doesn’t move with the table itself.) It’ll have an origin with an Y position and a Y position – x will be somewhere between 0 and 320, depending on how far right it needs to be placed. And the Y position will control how far up or down the screen it appears.

If we calculate the Y position by taking the height of the tableView's frame and multiplying it by the percentage that the table has been scrolled, the UIView will appear to move up and down the screen in proportion to how fat the tableView has scrolled. It’ll start at the top of the screen when the tableView is at the top, and slide down towards the bottom as the tableView is scrolled. It won’t leave the visible screen regardless of how long the tableView actually is, because we’re calculating the percentage of the tableView's frame rather than its content size.

Because UITableView inherits from UIScrollView, it means we can use the scrollViewDidScroll: method of UIScrollViewDelegate as the “trigger” for calculating how far things have scrolled, and adjusting the position of the UIView with the little clock icon.

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
 
// Work out positions
currentTablePosition = scrollView.contentOffset.y;
currentTablePositionPercentage = (currentTablePosition / workingTableHeight);
 
// Work out position of "block"
float blockOffset = (frameTableHeight * currentTablePositionPercentage);
 
float newYpos = 64 + blockOffset;
 
NSLog(@"tableView's scroll position = %f", currentTablePosition);
NSLog(@"blockOffset position = %f", blockOffset);
NSLog(@"current table position %%age = %f", currentTablePositionPercentage);
 
NSLog(@"New xpos = %f", newYpos);
 
theBlockView = theAppDelegate.theBlockView;
theBlockView.frame = CGRectMake(theBlockView.frame.origin.x, newYpos, theBlockView.frame.size.width, theBlockView.frame.size.height);
 
}

This is all *very* crude, not least because the calculations don’t take into account the size of the UIView that you’re moving around. Nor do they account for the fact that you can scroll a tableView or scrollView *beyond* 0% and 100% as it bounces at the top and bottom extents.

Path also takes things one stage further by figuring out which row the little icon thing is hovering over, and changing the value of the clock to reflect when the contents of that row were updated. There’s also some very neat animation as the clock times change by spinning the hands. But the basic principles of figuring out where the icon slider should be still hold.

UpdateFlorian Mielke has produced a much better explanation (and a library on Github) here

cxpartners | Resources

 
 

"These templates and resources appear in our book Communicating the user experience: A practical guide to producing UX Documentation"

http://www.cxpartners.co.uk/ux-resources/

“Steal Good Stuff” – iOS Design Pattern Collections | Cocoanetics

 
 

Collection of iOS design patterns / UI inspiration sites

http://www.cocoanetics.com/2011/11/steal-good-stuff-ios-design-pattern-collections/

InstaCSS | Instant CSS Documentation Search

 
 

Online documentation for CSS. Does what it says on the tin, really...

http://instacss.com/

BAMEasyTable

 
 

"BAMEasyTable is a subclass of UITableViewController that makes it easy to implement powerful tables in your app with minimal coding. This post explains how to use BAMEasyTable."

http://barrycenter.com/BAM!coding/2011/09/bameasytable-demo/

Jasmine: BDD for your JavaScript

 
 

"Jasmine is a behavior-driven development framework for testing your JavaScript code. It does not depend on any other JavaScript frameworks. It does not require a DOM. And it has a clean, obvious syntax so that you can easily write tests."

http://pivotal.github.com/jasmine/

Tangle: a JavaScript library for reactive documents

 
 

"Tangle is a JavaScript library for creating reactive documents. Your readers can interactively explore possibilities, play with parameters, and see the document update immediately. Tangle is super-simple and easy to learn."

http://worrydream.com/Tangle/

Bootstrap, from Twitter

 
 

"Bootstrap is a toolkit from Twitter designed to kickstart development of webapps and sites.
It includes base CSS and HTML for typography, forms, buttons, tables, grids, navigation, and more.

Nerd alert: Bootstrap is built with Less and was designed to work out of the gate with modern browsers in mind."

http://twitter.github.com/bootstrap/

Self-guided Ruby on Rails 3.1 Tutorial – Devalot

 
 

"One of the complaints about Ruby on Rails that I hear most often is its complexity, despite all the video tutorials showing how easy it is to build a simple application in 5 minutes. In reality, Rails was a huge paradigm shift for web application development and even with its complexity it's a great platform.

I've spent the better part of the last 6 years writing applications using Ruby on Rails and people often ask me for my perspective on how to bootstrap an application and best practices for using Rails. I also see a lot of people getting lost in the noise of scaffolding and complicated tutorials.

That's why I decided to write an example application using Ruby on Rails 3.1. The application is on Github to make it easy to get to, and takes advantage of source code control features like branches so you can follow along as the application gains functionality."

http://www.devalot.com/articles/2011/11/ror-example

Apps4Arduino – Matatino

 
 

Matatino is a Cocoa framework for Mac that provides a straight-forward way to communicate with your Arduino through its serial connection. To get started, visit our tutorial on how to add Matatino to your Xcode project!

Matatino was developed by RobotGrrl. Matatino uses AMSerialPort (with modifications from xcode-arduino-serial-communication). Matatino was based off of xcode-arduino-serial-communication.

http://robotgrrl.com/apps4arduino/matatino.php

 
 

About

Hello, I'm Tim. I'm a geek who builds online and mobile software and also takes photographs and messes around with technology. This is my personal website.

You can find out more about me and browse through the full archives. I also take photographs, and hack around with things. You can find me elsewhere on the interwebs, get in touch, or subscribe to a feed from this site.

Creative Commons License
The site's content is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 2.0 UK: England & Wales License, unless indicated otherwise. Please don't steal it :-)

About this site

This site is powered by Wordpress, and hosted by the nice people at Linode. The template is custom-built and based on 960bc and the 960 grid.