Circular Scrolling + Inertia

Why Inertia?

I’ve talked a lot on this blog about the circular scroll-view/table-view thing I created for my metronome app, and while I’m very pleased with how the whole thing turned out, I was still annoyed that I hadn’t figured out how to do one thing: give it inertia like UIScrollView. A commenter on one of the posts even asked me about inertia, and I basically just flat out said I’d like to, but it would be too hard! But after that, it just kept bugging me; there had to be a way. Inertial scrolling on iOS – and now on OS X too – just feels so nice. It’s one of those things that many people probably don’t even think about or notice until it’s gone. After feeling the smooth scrolling and realistic deceleration of UIScrollViews, my little rotary control just feels like garbage. I mean, come on, you give it a little flick and it stops rotating immediately when you lift your finger!? Lame! Frankly, my control just doesn’t feel quite completely at home on iOS yet, and I want to change that.

Maybe UIScrollView Can Help!

I got really exciting after watching the WWDC 2012 video for Session 223: Enhancing User Experience with Scroll Views. In the presentation, they give an excellent demo of how to leverage the physics of UIScrollView even when your app uses OpenGL. The UIScrollView is not used for any drawing, but by passing touches through it, listening for the scrollViewDidScroll, and reading the contentOffset, you can enjoy all the benefits of UIScrollView like inertia and edge bounce without actually drawing your content in the scroll view itself. Maybe, I thought, I can use that same trick on my circular scroller. Using the same techniques from the video, I was able to get up and running with the same circular action as well as a bit of UIScrollView provided inertia, but it just did not feel right at all. The geometry of linear scrolling and deceleration just don’t line up with what I need in terms of angular rotation.

Eureka!

The video technique didn’t work out quite like I had hoped, but I still took away one key idea: implement the inertia in the touch handler, not in the circular view itself. Seeing as how no one has seen the details of my implementation, that might not make sense to anyone but me right now, but I’ll try to explain. At its most basic, my control has two parts: the transparent view which interprets the touches as circular movements (a gesture recognizer, if you will, although it’s not an actual UIGestureRecognizer subclass) and the display view that receives notifications of those movements and rotates, swapping elements in and out sort of like UITableView cells. I had already implemented a bit of animation in the view component that allowed it to center on a certain cell, and I kept trying to think how I could make this also work with a longer rotation, and I was running into a lot of problems with the cell swapping during the rotation animation. But, if I implement the inertia on the control side and use the same delegate call for rotation that comes from an actual touch OR from the inertia, the view side doesn’t even know the difference. And it actually worked pretty well without much modification at all!

Check out the Repo

So, here’s the real/final point of this post: I’d love to get this whole rotation control thing (or most of it, at least) out into the wild as an open source component, but it’s been hard finding the time. It’s a fairly complex API, and I don’t feel like I can just release it without some more clarity and focus, as well as a nice sample project. So, I’m going to try to get it out there piece by piece if possible. I’ve put up a little bare bones project on GitHub – my first! – to test the waters. Let me know what you think, and of course, feel free to fork it and make it better. Right now it’s just a simple version of the rotation control view (RDDRotationControlSurface) which is hooked up to a UIViewController delegate that spins a UIImageView based on the input. Wow, that sounds way more complicated than it is – it’s just spinning a little picture of a very nice-looking German (or Austrian; can’t remember where this picture was taken) man in a cool getup. Don’t ask me why I chose this picture; it was there, and I went with it!

PS: You may be wondering why I didn’t go with a UIGestureRecognizer subclass for this. As far as I can tell, the gesture recognizer API would not work very well with something like this which needs to continue sending updates even after all touches have stopped. So, in the end, I’d still end up with a UIView subclass of some kind. Doesn’t mean GR couldn’t help here, but I just didn’t go that route.

Macro for Device Specific Settings (There’s a new iPhone Screen Size!)

iPhone 5

Well, it finally happened. Apple is releasing an iPhone with a different screen size and aspect ratio. “Oh no!” everyone screamed. iOS is headed down the path of Android! Fragmentation is here!! OK, there’s probably (almost ) no one actually saying that. Yes, there’s a new device, but the fragmentation situation for Apple – even including the various combination of screen size, processor type, iOS version, etc. – doesn’t even come CLOSE to that of Android. The fact is, Apple know what they’re doing. Agree or disagree with their reasoning for the iPhone 5′s new screen, it’s clear that they don’t take this type of change lightly. I mean, just listen to how Sir Jonathan Ive opens this video. How can you not agree with everything this man ever says?!

The first big “disruption” to the iOS ecosystem, was of course, the iPad. But guess what, Apple took careful measures to make sure that every single existing app would automatically run. I’m sure there were examples of apps that didn’t take to the simulated iPhone environment perfectly, but for the most part, everything just worked. And that was no small feat of engineering, I’m sure! Yes, we were all pushed to build native apps for the iPad, but they weren’t going to immediately alienate thousands of developers and millions of app users just because they decided to make a cool new device. The next disruption was iPhone 4 and Retina Display. Once again, great new technology for those who incorporate it, but in the meantime, existing apps for the most part ran just fine. And now, last week, the 4″ screen of the iPhone 5. But guess what, all existing apps will run just fine, only letter-boxed. But what about those who want to take advantage of this new technology, to create an app that makes full use of that new tall screen? Read more

Click – A Postmortem

The App

My latest app, an iPhone metronome called Click, has been out for two months now, so I thought this would be a good time to do a little postmortem reflection on the development process, the launch, and some thoughts for the future. I’ve discussed some of the development and design of the app before on my blog, but I haven’t yet done much discussion of how it all turned out. So, here goes…if you’re mostly just interested in the numbers, then skip to the end (although I’ll give you a hint: they’re not too large).

What Went Well

1. The Design

There are still some things I want to tweak, but overall I’m very pleased with how the general look and feel of the app came out. It was incredibly satisfying to go through the whole process of brainstorming ideas, testing them out, and then finally settling on a design and control scheme and actually seeing it come to life. It was definitely a learning process, and even though it was slow going, I can look back on my time spent with this project and know that it wasn’t wasted time. I was focused on creating a certain “look” for this specific app, but everything I learned about Core Graphics, UIKit, and Photoshop is instantly transferable and applicable to future projects. There were certainly times that I wanted to give up on the customization, throw in a few stock UIButtons and ScrollViews and just ship this stupid thing, but in the end I’m glad I stuck it out! Being able to turn your vision of what something could be into a real, working product is, for me, one of the greatest joys of software development.

2. The Features/Scope

I spent quite a lot of time and effort thinking through exactly which options and features I wanted to include in this app. The only real required feature of a metronome is that it produce sound at a regular interval (and yes, probably also with some type of visual feedback), and the only required option is to be able to set the tempo to the desired speed. This is all that a traditional hardware metronome does. But modern metronomes – of the software and the hardware variety – have so much more audio flexibility: time signatures, variable accent patterns, subdivide the beat in various rhythms, multiple sounds, storing setups for creating set lists or practice routines, programming longer sequences for specific songs, and on and on. There’s also many varieties of visual feedback available, especially in the realm of software metronomes. I made the decision that one of the key distinguishing features of Click would be the ability to select Read more

Interview with Beginning iOS Dev

20120710-211544.jpg

Sunset on The Great Salt Lake

I’m on day two of a three day move from Illinois to California right now, so I don’t have anything new ready for the blog. But, I didn’t want to miss my blogging slot completely, so I thought I’d link to an interview I did the other day over on the Beginning iOS Dev blog. Of you haven’t seen the website yet, you should take a minute to browse around. There are quite a few resources, and the interviews especially are interesting and very well done. There’s also a bit of a postmortem there of my app Click that’s been out for a while now if you’re interested in that. I may do a full write up on here sometime soon. In the mean time, one more full day of driving and we’ll finally be at our new home!

Some Good News and Some Bad News

I’m sure everyone is busy playing with the new bits from Apple right now, or lusting over the new hardware just announced, so I’m not sure who all will see this, but it’s my slot today for iDevBlogADay, and I’ve got some news to share, so I’m going for it!

I’m so mad at myself right now. The good news is, my new metronome app “Click” was just approved and is Ready for Sale!! The bad news is, I used a promo code to download it before releasing it for sale, and… it’s got a bug. A big ol’ freaking whopper of a bug. Somehow as I finalized my image assets, one of the resources had the wrong name in the Nib file – there was an “@2x” left on the end of the image name in the Nib configuration for the UIImageView. The app runs and loads fine in the simulator, and I swear the final build worked fine on my device too, but apparently the App Store release build is more picky and couldn’t locate the resource. So, one of the key pieces of the interface is invisible. So guess what? I’ll be waiting another week at least for another review. I could possibly ask for an expedited review, seeing as this is a “critical bug,” but the problem is the app isn’t actually even for sale yet, so it’s not like the bug is actually “live.” I don’t really wanna push my luck and/or annoy the review team now and then really need an expedited review later. So, one lesson is, keep testing the crap out of your app even after you submit, and you just might catch something and be able to developer reject your binary before the review starts. The other, real moral of the story is: delay the release of your app at least enough to generate a promo code and try out the released version for yourself. I have no idea when promo codes started working for apps before they’re actually released, but it certainly saved me this time! My thanks to @wtrebella for bringing this to my attention when he was tweeting about releasing Polymer.

I must say though, this isn’t all bad. I’ve been working on this app for over a year. I’ve been wanting to integrate a quality metronome into another app of my, theDrumDictionary, and in future music-related apps. So, this was supposed to be a quick side project in learning Core Audio and how to make a metronome, and since I was going to do it anyway, I figured, why not release a standalone metronome app too? But I didn’t want to make just another metronome app, and as I explored how to differentiate mine from the existing options, it sort of exploded into this very large project with difficult to implement (for me) custom controls and a large amount of Photoshop time designing a unique UI. Needless to say, I’m ready to get this thing out there and see what happens! When it comes to an initial release, I actually came to appreciate the sort of built in waiting period of the app store review time. Being forced to stop coding, it was a great chance for me to finalize my press materials and continue to get the word out about the new app. I was expecting to be done a *lot* sooner than how it turned out, and by the time I submitted the app for review, I knew I was going to be running right up against WWDC. Who’s going to care about some no-name company’s metronome app in the middle of big hardware and software announcements?! If approved during dub-dub, how long should I wait to release the app? Or should I release the app, and just wait until later to do press releases, etc.? Or is it really most beneficial to do a launch all at once – app appearing on new releases, press release, etc? (Great articles from Justine Pratt on marketing, by the way!) Well, now I don’t have much choice! I’ve probably got another whole week to keep up the marketing prep, spread the word to existing DrumDictionary customers, etc., and there’s not much worry about WWDC anymore. I’ve got to release this sometime, and a whole week after the big keynote seems like as good a time as any to me; it’s certainly much better than anytime this week. And, I can confidently run a full on launch blitz with no fear that I’m messing it up by separating the app release from the press release OR driving myself crazy as I wait for days for the right marketing timing knowing that it’s just sitting there ready waiting for me to change the availability date. I suppose I shouldn’t be too mad about it after all! (but let’s face it, I’m pretty pissed). Anyway, maybe this gives you something to think about before you release your next app! And, if you’re curious, head on over to my new Gig Bag Apps website and check out the trailer for Click. Maybe it’ll be a hit; if I ever actually release it :-)

UIKit and GCD

Graphics Bottlenecks

Creating a responsive user interface is one of the most important considerations for a mobile developer, and the smooth scrolling and quick responsiveness of iOS has been one of its hallmarks since day 1. — I’ve gotta be honest here; I still find myself every now and then finding great amusement in just flicking around a simple web view or scrolling some text on my phone. It just feels so right! — Keeping a smooth flow and one to one correspondence between user touch and visual display is crucial for maintaining the illusion and feeling that one is directly interacting with the objects on the screen. One key consideration to make this happen is do not block the main thread. If you are doing anything that might take a significant amount of time, you must do this on a background thread.

With iOS 4.0 and the introduction of blocks and Grand Central Dispatch, it became much easier to complete tasks in the background asynchronously without having to dive into the implementation details of threads and such. If you haven’t yet tried out GCD, take a look at the docs, or check out this tutorial to get you up and running quickly. It’s great for parsing data, downloading from the network, etc. off the main thread, and GCD makes it very easy to write code that will call back into the main thread once the background process completes. What it doesn’t work well for is anything to do with UIKit or the user interface. All drawing and touch interaction takes place, by design, on the main thread. So, what do you do if your drawing itself is taking too long and blocking the main thread? I’m sure there were people much cleverer than me who found some ways to get around it and do some drawing in the background, but basically up until iOS 4, UIKit was not thread-safe at all. If your drawing is too complicated and blocks, then you need to optimize it or simplify it. However, the release notes for iOS 4.0 contain the following short section:

Drawing to a graphics context in UIKit is now thread-safe. Specifically:

  • The routines used to access and manipulate the graphics context can now correctly handle contexts residing on different threads.
  • String and image drawing is now thread-safe.
  • Using color and font objects in multiple threads is now safe to do.

This was not something I had really been interested in or concerned myself with until I ran into just such a problem recently. I created a custom subclass of UILabel which adds a colored, blurred shadow to the label to give it a glow effect. But, this drawing took drastically longer than the regular string drawing. For example, for the drawing that happens at app startup, using regular UILabels takes 104 milliseconds total in drawRect:. To draw the exact same strings with shadows takes 1297 milliseconds! So, you can imagine what this does to frame rates when there are multiple labels being updated rapidly during an already CPU intensive section of the code.

Multi is fun threading!

Since I already know ahead of time exactly what strings I need to display during this particular bottleneck, it would be nice to be able to draw all the labels at once in the background and cache them for later. My first approach was, Read more

Photoshop Layer Comps

Just a quick Photoshop tip today, but it’s something I’ve been making extensive use of the last few weeks, so I thought I’d share. If you happened to read my last post and/or watch the video, you would have seen that in my new metronome app, I’m handling interface rotation in a somewhat different way than most apps. Rather than using the standard system autorotations – using the usual springs and struts in Interface Builder or the UIView’s autoresizingMask property – I’m leaving the basic layout of the controls the same and just rotating the contents. It’s kind of hard to describe, so if that doesn’t make sense, skip to about the 10:00 mark on this video.

Here’s the gist of the code to make this happen:

  • In the main ViewController’s shouldAutorotate method I only return YES for  UIInterfaceOrientationLandscapeRight, the same orientation the app launches in. Meaning, the view controller will not do any auto-rotating once it’s loaded into its initial state.
  • I’ve registered for the UIDeviceOrientationDidChangeNotification. Even though the View Controller will not do anything automatically when the device is rotated, the system will still generate these notifications when the orientation changes.
  • When I receive this notification, I pass the message along, and the individual views apply whatever sort of rotation transform they need to in order to remain “right side up.”
  • If the Status Bar is visible, you can also programmatically set its orientation with:[[UIApplication sharedApplication] setStatusBarOrientation:(UIInterfaceOrientation)orientation animated:YES];

What this means from a design perspective, is that the UIImageViews themselves, which contain the main interface chrome, do NOT rotate at all. So, here on the right is what the main control frame looks in the launch orientation – notice the shadows, gradients, etc. all use the “canonical” iOS 90 degree light source.

Let’s say the user then rotates to LandscapeLeft – my subviews will rotate themselves, but the image will stay exactly the same. The image on the left is the same, but rotated 180 degrees. It’s strange how much different – and more noticeable – the light/shadow/gradient effects are when they’re flipped around the wrong way!

So, in order to maintain the right look, what I need to do is create separate images for each orientation and load these in as part of my custom rotation handling. Here’s where Photoshop layer comps come in. What they let you do is take snapshots of certain aspects of your document state and then reload them with one click. For example, in my case, I’ve set up one Layer Comp for each of the four orientations I’ll support. Here’s the workflow:

  • Setup the document for the current orientation. In the case of LandscapeRight, that means 90 degree light sources for all drop shadows, gradients that go light to dark from top to bottom, etc.
  • In the Layer Comps window – add it to the toolbar from the Window menu if you don’t see it – select New Layer Comp from the pulldown menu.
  • In the dialogue box that opens, give your comp a name, select which parts of the document state you want to be saved as part of the snapshot, and add any helpful comments you might have. 
  • For this particular case, I’ve told the Layer Comp to only save the Layer Styles of the document’s layers.
  • Repeat the process for each orientation, setting the light sources, gradients, etc. on the Layer Styles, and then saving it as a new Layer Comp.

By using vector/smart objects and layer styles – you are doing that aren’t you? – the exact same set of objects and layers is used for every orientation. I’m free to adjust the positioning, size, and shape of the objects, and then, when it comes time to export for each orientation, I just click through the four Layer Comps one by one, and all my light and shadow effects are applied instantly to all objects. It takes a bit of work to setup, but once it’s ready, it saves huge amounts of time over going to each object individually and resetting the properties every time I want to make a change in the design and re-export for each orientation. For things like the “Tap,” “+,” and “-” labels, and for different button states, I also have a set of Layer Comps which control layer visibility. So, for example, if I need to re-export the image for the “pressed” tap button – I hit the Layer Comp for the orientation I want, which loads the correct layer styles, then hit the “Tap Button Pressed” layer comp which won’t affect the layer styles, but will hide the normal Tap button layers and show the pressed ones. Two clicks and I’m ready to export. So, that’s how I’ve been using Layer Comps in my particular case to speed up my design workflow – hopefully it gives you some ideas for how you might be able to use them in your own workflow!

Follow

Get every new post delivered to your Inbox.