Stylesheets in Swift

In each of my apps I'm using some kind of a collection of basic information describing the app's general look and layout, which I'm calling stylesheets. With stylesheets, styling an app becomes more easy, more consistent and having one also makes implementing features like themes-support much easier. As I'm using and relying on stylesheets for each of my apps, I'm always searching for a better way to build and use these stylesheets.

My last project used an approach I was pretty happy with, but lately I first stumbled upon an interesting blog post by @natashatherobot and shortly after upon a nice talk by @preynolds_, which both inspired me to rethink and refine my approach once again.

My newest approach makes heavy use of Swift's caseless enums to define namespaced constants in a stylesheet and extensions for applying the stylesheet on your UI elements. (Make sure to read the blog post and watch the talk I linked above to learn more about these concepts!)

This is what an (shortened) example stylesheet could look like with the new approach:

It's basically just a collection of nested enums with static constants. Inside the main Stylesheet enum, you can define more enums for your stylesheet's categories like Colors, Fonts, Assets or Contexts. In each of these categories, you can get more specific by creating another level of nested enums and so forth.

This approach is very flexible, as you can create and nest enums for all kind of elements/categories you may need in your app in a way that best fits your requirements. It doesn't rely on any standard and can be fully adjusted and extended to your needs.

These are just a few (personal) thinkings behind the basic categories I typically use:

Colors/Fonts/Assets/...:

  • elements in these categories can be accessed directly, but are preferred to be accessed via Contexts (you could also make a category private to enforce this rule)
  • name of an element should describe the element itself, not its intended use

Contexts:

  • the main outlet when using the stylesheet from anywhere in your app
  • each context refers to a scene or even a specific class in your project
  • contexts mainly reference constants defined in other categories by redefining them, now named after the specific & intended use

As there is no way to actually create an instance of any of the enums, your stylesheet floats around your whole project as a list of namespaced constants and you don't need to create multiple stylesheet-instances, use a singleton or pass one instance through your whole app from the AppDelegate to each ViewController and View. (looking back embarassed on past approaches)

There are many ways you could then proceed with actually using the Stylesheet and its elements in your project, but I particularly liked the way shown in the talk which inspired me, namely using Extensions.

You could place this extension wherever you want, e.g. directly in the class you want to apply the stylesheet on, or you could even have one extra file for your stylesheet-extensions where you insert a applyOn method for all of your classes. I've used the one-extension-file approach in my example project and it's really nice not having to search in x amount of different classes for something UI related, but having it all in one central place.

@preynolds_ gives some good additional advice and examples how this approach can make collaborating with designers more efficient in his talk, so if you are working closely with designers, make sure to watch it!

Example project on GitHub

I've created a small example project with a few controllers and views to show off this approach, you can find it on GitHub.

I welcome any positive or negative feedback on this approach and how to further improve stylesheets in Swift. If you have suggestions, tell me on Twitter or via mail and I'll make sure to update this post or write a follow-up.


Transparent Background Views

While working on one of my side projects, I wanted the app I was working on to have one background view, that’s visible in all viewcontrollers and while transitioning between them.

My first idea was to add the background view to the app’s main window and make each viewcontroller’s view transparent. That didn’t really work out as expected, because transparent views seem to make the UINavigationController’s default transitions glitch out.

iOS Default Transition with transparent views

But it’s actually pretty close to what I wanted to achieve, so (after some other failing attempts) I tried coming up with a custom transition to see whether the views would still glitch out. Turns out they don’t! With a custom transition, the result looks fine.

iOS custom transition with transparent views and one background

The transition itself is actually pretty easy and straight-forward:

1: In the transition’s init method, the start and end frames for the views participating in this transition are calculated. The calculation incorporates the UINavigationController’s transition operation (e.g. push or pop) and is done using a simple helper-struct.

2: In this method, the transition is layed out and performed. At first we grab both viewcontrollers and check whether the containerView was created.

3: The containerView acts as the superview for the views involved in the transition and must be used as the container for all other views involved in the transition. Thus we add both our viewcontroller’s views to it.

4: These lines are needed to make Auto Layout happy. If you don't include these lines, there's a good chance your UI elements will be lay out wrongly after the transition.

5: Here, the sliding animation is prepared. The toViewController should be sliding in from the left (pop) or right (push) side of the screen, so it needs to be positioned just outside the screen’s bounds right before the animation kicks in.

6: This is where the transition is performed. All we need to do to achieve the sliding effect is setting the frames the viewcontrollers should have at the end of the transition. In the completion block, we need to tell the transitionContext that the transition was actually completed.

Next, we need to connect our custom transition with an UINavigationController instance. I did this in my AppDelegate:

1: Create an instance of NavigationControllerDelegate (defined below).

2: Create an instance of a standard UINavigationController instance and set the delegate.

3: In the delegate method for the transition to be used within the navigation controller, simply return the custom transition.

That’s it! The custom transition is set up and ready for use. In my case, I also added a custom background view to the window and set the viewcontroller’s background colors to clear.

I published the full source code of a working example for an app with one background view, transparent viewcontrollers and not-glitched-out transitions on Github: AppWideBackgroundExample.


New Job

I resigned my job as a (non-iOS) software developer at my old company earlier this year and on monday this week, it was my last day. I had a great time with wonderful colleagues there for the past 4 years, but now I'm looking forward to an exciting new chapter in my career: I'm starting a new job as an iOS developer on March 1st.

After spending 3 1/2 years with iOS development in my free time as a hobby, I'm very excited to be able to say that's my real job now!

My 12 Months, 6 App series from last year surely helped a lot with getting there and I'm still working on a longer blog post summarizing my experience & the series as a whole, which I'll publish soonish.


Coordinates (Release)

It's a wrap! My last app for #12M6A launched today.

Download Coordinates for Minecraft on the App Store

More Information about Coordinates for Minecraft can be found on its App Page.

So with this app being released, I successfully hit my personal goal for this year to launch 6 apps in my freetime. A detailed blog post about this will follow early next year!


Key Task (Release)

Almost there! My penultimate app for #12M6A was released today.

Download Key Task on the App Store

More Information about Key Task can be found on its App Page.


Spinning Shots (Release)

And another one I can cross off my list! Spinning Shots, the fourth app for my #12M6A series was just released on the App Store. As with all previous apps I published in the series so far, it is available for free.

Download Spinning Shots on the App Store

More Information about Spinning Shots can be found on its App Page.


Plumatch (Release)

Today I'm happy to announce that Plumatch is now available for free on the App Store. Plumatch is the third app I release as part of my ongoing 12 Months, 6 Apps series.

Download Plumatch on the App Store

More Information about Plumatch can be found on its App Page.


App #3 - Complications Demand Decisions

Last week, I wrote on Twitter:

The (not yet announced) third app for #12M6A is coming along nicely. Probably can be submitted in the next 3-7 days!

Fast forward to today, exactly 7 days later: I haven't submitted the app yet. And it won't happen for a few weeks at least.

That's because there is an error in my Xcode 6 project (similar but not identical to: 1,2,3,4), which I was not able to resolve. Yesterday I rebuilt the entire project from scratch using the current Xcode 7 beta, received the same error at some point, but was able to resolve it using some of the steps from the above-linked Stack Overflow answers, which however didn't resolve the same error in Xcode 6 for some reason.

So I'll wait with submitting the app until Xcode 7 comes out of its beta status and it's possible to submit apps to the App Store with it, a few weeks before iOS 9 drops.
I could try to get it working in Xcode 6 further on, but I already wasted too many evenings on this problem and it's just not worth my time anymore.

Development for the app is almost completed, as is the creation of the other resources needed for its submission. I'll wrap it all up and just wait until it's possible to submit with Xcode 7 and then do so.
In the meantime I can already start working on the next project and won't lose any more time struggling with weird Xcode issues.

P.S.:
Because the release of iOS 9 is so close by and I have to wait for it (respectively Xcode 7) anyway, I'm now thinking about targeting iOS 9 instead of iOS 8. I was busy developing Viable and app #3 for iOS 8 since the new iOS 9 api's were introduced at WWDC and thus haven't looked much at the shiny new bits yet. That's another decision I'll make in the next few days.

Update: Someone cheered too soon. The problem came back after a few days in Xcode 7 as well. I'll take a look at it sometime soon, but for now this project is cancelled/deferred. Working on the next one already.


Viable (Release)

It's happening! Viable is now available on the App Store - for free!

Download on the App Store

More information about Viable can be found here: Viable App Page.


Viable - App Number Two for #12M6A

A little more than a week ago, I submitted my new app called Viable to the App Store. It’s the second app I’ll release as part of my ongoing #12M6A series.

Here’s a short trailer:

View on Youtube

I’m waiting to announce the release date until the app is approved by Apple, but my current estimate would be the second week of July.
(Update: Viable will launch on July 16th! )

When I started planning my #12M6A series at the beginning of the year, I hoped I would release my 3rd app already at this time of the year. Of course this will create some tension for the residual part of the year, as I do have to develop the remaining four apps in a noticeable shorter amount of time than I had originally planned. But I’ve got some nice ideas and am confident everything will thrive well and smoothly.

The delay was mainly caused by the finals of my apprenticeship, which took place in the first half of this year. Today was my last exam and I successfully passed it! Hopefully I’ll be able to shift some more of my free time towards #12M6A now that they are done :)

(Update #2: Viable is out now )