Introduction
In this post I look at PixelCuts PaintCode 3 and how you can use it to quickly build user interfaces in Xcode, I will talk about how this can be useful and areas where other solutions may be better.
When starting iOS development building custom UI in Xcode can be pretty daunting as you need a good understanding of apples UIKit framework and how to subclass from it to get your desired behaviour, getting the desired look difficult when viewing in a storyboard as you need to implement @IBDesignable & @IBInspectable.
PaintCode in some scenarios can be used to make this process easier, for example you can define a set of colours and buttons in PaintCode and export them into swift, if you want to update a colour you can just update in PaintCode and re-export.
The inspiration
I first saw PaintCode when a college was using it to draw a smile/sad face based on a user satisfaction score, which really interested me as you could control the drawing with outside variables.
This reminded me of an idea I had for a small guitar tuner app where I wanted the UI to respond to the notes being played and let the user know if they were in tune.
Initially I wanted to make something quirky rather than a standard dial tuner for example an animated flame that grew and changed colour the closer you got to being in tune. I however quickly realised that PaintCode is not an animation library but rather a drawing library that could redraw given new parameters, this wouldn't quite fit the flickering flame idea I had without much more outside of PaintCode.
I instead opted to recreate the look of my favourite physical tuner "polytune". I have one of these, but it isn't always practical to set up for a quick tune and the led matrix it uses is an interesting interface to recreate in an app. Although polytune gets its name from being able to tune several notes at once, I'm going to keep my focus on tuning one note at a time.
The work
This is not a tutorial so I won't be giving a step by step account on how I built this but rather an overview of features used to achieve it.
One nice feature of PaintCode is "symbols" this gives you the ability to compose several canvases to create a UI, any changes to the symbol in its canvas will update in all canvases that use it as a symbol. Below is a screenshot of the different canvases that make up the UI.
The "Tuner Matrix" is made out of "Vertical matrix" which in turn are made out of "LED".
The "LED" symbol handles its own appearance based on its inputs, which are "luminosity" (how opaque the oval is) and "isPositive" (positive is green and negative is red).
The "Vertical Matrix" also handles luminosity for that vertical section which gets passed to the LED symbol as it lights up like a needle moving horizontally, it also handles whether or not it's the centre position where all LEDs will be positive.
The "Tuner Matrix" takes a "tuning Distance" input which will be between -1 and +1 with 0 being in tune and central.
To indicate the tuning each Vertical Matrix has it's own expression variable for its luminosity where it will be which looks at the tuningDistance and updates for example the centre will be something like:
tuningDistance > 0.4 && tuningDistance < 0.6
? 1 : tuningDistance > 0.3 && tuningDistance < 0.7
? 0.5 : 0.2
The nice thing here about PaintCode is the ability to update the variables and see the canvas redraw in real time which made it much easier to adjust the expressions to get the look and the sense of how it will respond in the app.
Exporting to Xcode
When exporting there are several options to choose from, originally it was recommended to copy and paste the code outputted but now the recommended approach is where you export as a "StyleKit", this is essentially a class that contains your drawing methods, colours, gradients, shadows and images in a single place that can be used in Xcode.
StyleKits are really useful as you can use colours from your canvases in text and other areas of your application, and if chosen you can also use your drawings as images.
To get my Tuner Matrix working, I created a new subclass of UIView and overrode the draw method to use my TunerStyleKit.drawTunerMatrix method then passed in the frame and tuningDistance parameters.
After implementing @IBDesignable & @IBInspectable I could see the drawing in the storyboard and update the variable for tuning distance in the inspector to check everything was redrawing correctly.
Adding extras
I also wanted to get that LED display look for the note output, so I also added a "Tuner Note" canvas with a note input and an accidental input (sharp and flat symbol) with a custom font. This could have been implemented just in Xcode and then use the colour from the StyleKit as I also had to add the font to Xcode however i think because this is so closely tied to the tuner matrix that it makes sense to include it in the PaintCode file so any changes to shared colours could be seen together. To connect it in Xcode, I then implemented it in much the same way as the tuner matrix.
Final thoughts
PaintCode is a good piece of software, I really like the ability to compose canvases using symbols and being able to use colours as variables gives some really nice control along with the expression variables. One frustrating part for me was scaling using "frames" this looked promising, but you can't have control when using objects that have scale or transformations applied and frames don't interact with ovals in the same way which made the Tuner Matrix more difficult to reason about when it came to being dynamic in size, with much frustration I still could not scale whilst keeping the aspect ratio with frames, this may be a drawing limitation expressed through PaintCode rather than a Problem with PaintCode.
Whilst I enjoyed using PaintCode and see some major benefits in certain cases I hesitate to recommended it with the new monthly subscription price tag as only a few people could justify that much use.
The best scenarios to use this would be applications that use complex visual interfaces that would require drawing and responding to input for example dials, loaders and other custom UI. If you're looking for animations this software isn't for you but QuartzCode might be what your looking for (as yet untested).