Quantcast
Channel: Kodeco | High quality programming tutorials: iOS, Android, Swift, Kotlin, Unity, and more
Viewing all articles
Browse latest Browse all 4399

PaintCode Sketch Plugin Tutorial

$
0
0

PaintCode-SketchPlugin-feature

Recently, an issue came up on a map clustering library that I support. Someone asked how to change the size and color of custom map markers and clusters. After some Googling, this didn’t look like an easy fix. So I gave a cop out answer and said to just use hard-coded PNGs.

The next day, I found out about the new PaintCode Sketch plugin. This was just what I needed — it’s a plugin that automatically generates Swift code for your Sketch illustrations. I tried it out in my app and was making dynamically sized and colored map markers in no time!

The PaintCode Sketch plugin is great because it helps bridge the gap between design and implementation. Designers can now deliver icons as Swift code instead of littering Slack with PNGs. As a bonus, the PaintCode plugin exports colors as UIColor objects — no more stringly-typed hex values!

In this tutorial, you’ll get hands-on experience with the new PaintCode sketch plugin by exporting a Sketch illustration and using it in an app. You’ll learn how to dynamically size the image and modify its colors and other properties. Let’s dive in!

Paint Code Sketch Swift Comic

Getting Started

Here’s what you need to export Swift Core Graphics code from Sketch:

Note you do not need a copy of PaintCode 2 to do this; the PaintCode Sketch plugin is an independent product that exports the Swift Core Graphics code for Sketch illustrations, without the need for PaintCode 2 itself.

Start by installing Sketch and the PaintCode Sketch plugin.

Then, download this Sketch starter file which you’ll use to generate Swift code. This tutorial does not require any Sketch skills, but check out this Sketch Tutorial for iOS Developers if you want to learn some basics.

Note: Alternatively, if you’d prefer to skip exporting the code for the Sketch illustration and jump straight into using it in an app, you can skip to ahead to the Working with the Objective-Tea Starter Project section. I’ve used Sketch and the PaintCode Sketch plugin to export the Sketch illustration to Swift code, and have the pre-generated Swift file waiting for you.

Preparing the Sketch File

Open the starter Sketch file and take a look around. Inside the main canvas area, you’ll see an image of a bubble tea cup. Below the image, there’s a color palette with nine colored squares.

Sketch layer names

On the left, there’s a panel called the Layers List. Each layer has a name like liquid, bubbles, or Mango. PaintCode will convert these names to variables and comments. It’s important to use meaningful names, because this makes the generated code easier to read.

Prep the icon

Before you jump into using the PaintCode plugin, you need to do a little prep work. First, you’ll nest the bubble tea cup image inside an Artboard.

  1. Hold down the Space key and drag the canvas to pan around until you see the image.
  2. Click Insert\Artboard from the main menu (or use the shortcut key A).
  3. Drag your mouse to create a rectangle around the image.
  4. In the Layers List, rename the Artboard to BubbleTeaCup.
  5. To center the image within the Artboard, select the blue folder icon and drag the image until it snaps to the red line guides.

Create an Artboard around the bubble tea cup

By organizing layers inside an Artboard, you’re letting PaintCode know that you want to treat them as a single image. So if you have multiple icons, you should place each one inside its own Artboard.

Prep the color palette

Besides images, you can also make a color palette. Just create an Artboard named Library and drop in some shapes with different colors.

  1. Type the A key to use the Artboard tool.
  2. Drag your mouse to enclose all the colored squares.
  3. In the Layers List, rename the Artboard to Library.

Create a Library Artboard

PaintCode converts each of these shapes into an UIColor object, using the layer name and fill color. The type of shape doesn’t matter. PaintCode ignores the border color and width as well.

Pro tip: The Library also supports gradients and shadows too. Just create a shape using one of these properties from the right inspector panel:

RC-gradientShadow

  • Gradient: Inside the Fill picker, choose Linear Gradient to produce a CGGradient.
  • Shadow: Click the plus sign + next to Shadows to produce an NSShadow. Just make sure you de-select the Fill checkbox so that PaintCode knows your intentions.

Using the Plugin to Generate Swift Code

Now that your layers are properly named and organized into Artboards, it’s time to generate some Swift code. From the Plugins menu, select PaintCode.

Select PaintCode from the plugin menu

Sketch will drop down a plugin sheet with different options.

Paint code options sheet

  • PaintCode Plugin: Register a license key or purchase one on the website.
  • Choose Drawings: Select which items you wish to export as code.
  • Platform & Language: Choose between Swift and Objective-C.
  • Settings: Add project meta data to populate the comment block at the top of the generated Swift file. Note that the Class Name defaults to StyleKit.
  • Change Code Settings…: Configure code formatting options, like indent using 2 spaces.
  • Get Code Files: Export the file to the Desktop, or drag the Swift file icon to a Finder window.

For now, make sure Library and BubbleTeaCup are checked; otherwise, leave the options as their defaults. Then select Export, and PaintCode will save a file named StyleKit.swift to the Desktop.

Working with the Objective-Tea Starter Project

All of the steps related to Sketch are behind you now. From here on out, it’s just Xcode, baby!

Download the starter project for this tutorial here. The zip file contains an Xcode project for a fake bubble tea app, Objective-Tea. In this tutorial, you’ll work on an order page where thirsty iOS developers can choose drinks of different flavors and sizes.

RC-ObjectiveTeaLogos

Launch the ObjectiveTea.xcodeproj file, then build and run. You should see a two tabs:

  • Order: Customize your bubble tea order.
  • Stores: This is a map with store locations.

Starter project screens

Your job for the rest of this tutorial is to liven up the app with colors and dynamic images.

Note: If you jumped straight to this section, download this zip file and move the StyleKit.swift file to your Desktop.

Import the StyleKit File to Xcode

By default, PaintCode uses the name StyleKit as the class and file name. Import this file into the ObjectiveTea Xcode project:

  1. Drag the StyleKit.swift file from the Desktop into the Project navigator, right above Main.Storyboard.
  2. Make sure that Copy items if needed and the ObjectiveTea target are selected.
  3. Click Finish.

Import StyleKit into Xcode

You should end up with a StyleKit.swift file in your Xcode project.

Working with Colors

At the top of the file, you’ll see a Colors section. PaintCode generates a static constant for each colored square inside the Library Artboard.

//MARK: - Colors
 
static let plum = UIColor(hue: 0.126, saturation: 1, brightness: 0.804, alpha: 1)
static let strawberry = UIColor(hue: 0.002, saturation: 0.369, brightness: 0.945, alpha: 1)
...

Set the tab bar color

Let’s test out one of these colors on the tab bar icons. The sample project already has a TabBarController subclass wired up in the Storyboard.

Within TabBarController.swift, add the following line inside viewDidLoad():

tabBar.tintColor = StyleKit.rWGreen

Build and run. The tab bar icons should be green, just like the tea leaf on the app icon.

Green tab bar tint

Set the flavor colors

All of the flavors are gray, which is not very appetizing. Next, you’re going to integrate the rest of the StyleKit colors into the app.

Within OrderViewController.swift, there’s a flavors array that generates all the flavor objects. Each of these flavors are using gray as a placeholder color:

let milkTea = UIColor.grayColor()
...
let milkTeaFlavor = Flavor(name: "Milk Tea", color: milkTea)

Replace each flavor’s color with the StyleKit version:

let milkTeaFlavor = Flavor(name: "Milk Tea", color: StyleKit.milkTea)
let coffeeFlavor = Flavor(name: "Coffee", color: StyleKit.coffee)
let taroFlavor = Flavor(name: "Taro", color: StyleKit.taro)
let matchaGreenTeaFlavor = Flavor(name: "Matcha", color: StyleKit.matcha)
let mangoFlavor = Flavor(name: "Mango", color: StyleKit.mango)
let strawberryFlavor = Flavor(name: "Strawberry", color: StyleKit.strawberry)
let plumFlavor = Flavor(name: "Plum", color: StyleKit.plum)
let yogurtFlavor = Flavor(name: "Yogurt", color: StyleKit.yogurt)

Build and run. Each flavor should now have a pretty color.

Bubble tea colors

Canvas Drawings

The next section of the StyleKit file includes canvas drawing methods. This section does all the heavy lifting of drawing vector paths. The code also looks pretty intimidating. Just be glad you didn’t have to write it by hand =].

Open StyleKit.swift and find drawBubbleTeaCup(frame:resizing:). You’ll see it looks similar to the following:

//MARK: - Canvas Drawings
 
/// ObjectiveTea
class func drawBubbleTeaCup(frame frame: CGRect = CGRect(x: 0, y: 0, width: 161, height: 221), resizing: ResizingBehavior = .AspectFit) {
  /// BubbleTeaCup
  do {
    /// Liquid
    let liquid = UIBezierPath()
    ...
    /// Straw
    /// Cup
    /// Bubbles
    /// Smile
  }
}

PaintCode adds comments based on the layer names from the Sketch file to help make the code a little more readable.

The drawing method takes two parameters:

  • frame: You can set the image size by passing in a CGRect. Otherwise, it defaults to the dimensions from the Sketch file.
  • resizing: You can pass in a content mode such as Aspect Fit, Aspect Fill, Stretch, or Center. PaintCode provides a helper enum at the bottom of the file to produce these effects.

Create a custom view

The canvas drawing methods are designed to work with custom views.

Open up BubbleTeaCup.swift. This is an empty UIView subclass that’s already wired up in the Storyboard:

import UIKit
 
class BubbleTeaCup: UIView {
}

Replace the file’s contents with the following code:

import UIKit
 
@IBDesignable // 1
class BubbleTeaCup: UIView {
  override func drawRect(rect: CGRect) {
    StyleKit.drawBubbleTeaCup(frame: bounds) // 2
  }
}
  1. IBDesignable: Gives you an image preview in the Storyboard.
  2. drawBubbleTeaCup(frame:): Draws the vector image into the current graphics context. You pass in the bounds so the image takes up the entire view.

UIView has a method called drawRect(_:) which provides a graphics context (which I like to think of as a piece of scrap paper). The drawBubbleTeaCup(frame:) method takes care of drawing the image on this piece of paper, which then ends up on the screen.

Open Main.storyboard and look for the OrderViewController scene. You should see a preview of the bubble tea cup, thanks to @IBDesignable.

IBDesignable custom view

Build and run. The bubble tea cup image should now appear on the order tab.

Custom view shows up

Canvas Images

Switch back to StyleKit.swift and find the imageOfBubbleTeaCup(frame:resizing:) method. You’ll see this converts the drawing method to its UIImage equivalent:

//MARK: - Canvas Images
 
/// ObjectiveTea
 
class func imageOfBubbleTeaCup(size size: CGSize = CGSize(width: 161, height: 221), resizing: ResizingBehavior = .AspectFit) -> UIImage {
  var image: UIImage
 
  UIGraphicsBeginImageContextWithOptions(size, false, 0)
  StyleKit.drawBubbleTeaCup(frame: CGRect(origin: CGPoint.zero, size: size), resizing: resizing)
  image = UIGraphicsGetImageFromCurrentImageContext()
  UIGraphicsEndImageContext()
 
  return image
}

Each canvas image method takes two parameters:

  • size: This takes a CGSize. Otherwise, it defaults to the dimensions taken from Sketch.
  • resizing: The content mode is forwarded to the drawing method.

This method can be useful in situations where you just want a UIImage of the drawing at a particular size.

Set the map marker icon

Let’s test out the canvas image method on the Stores tab.

Open StoresViewController.swift and scroll to the bottom. The map uses a hard-coded PNG for the map marker:

pinView?.image = UIImage(named: reuseId)

Replace this line with the following:

pinView?.image = StyleKit.imageOfBubbleTeaCup(size: CGSize(width: 32, height: 32))

Here you set the MKAnnotationView image to a 32×32 icon of the bubble tea cup.

Build and run. You should now see little bubble tea cups at each store location.

Map markers

Set the tab bar icon

You can also use the canvas image methods to set tab bar icons.

Open TabBarController.swift. The viewDidLoad() method looks like this:

override func viewDidLoad() {
  tabBar.tintColor = StyleKit.rWGreen
}

Append the following code, right after the tintColor line.

let tabBarIconSize = CGSize(width: 32, height: 32) // 1
if let firstTabItem = tabBar.items?.first { // 2
  let bubbleTeaCupImage = StyleKit.imageOfBubbleTeaCup(size: tabBarIconSize) // 3
  firstTabItem.image = bubbleTeaCupImage // 4
  firstTabItem.selectedImage = bubbleTeaCupImage // 5
}

Let’s go over this line by line:

  1. Creates a CGSize of 32×32, which seems like a good size for this particular icon.
  2. Gets a handle to the first tab bar item.
  3. Generates an UIImage of the bubble tea cup.
  4. Sets the tab bar item image.
  5. Sets the selected image.

Build and run. You should now see the bubble tea cup icon in the tab bar. Since tab bar items use template images, you won’t see the individual bubbles.

Tab Bar icon selected image

Using different image sizes

The app has an order tab where you can customize your beverage. Although there’s a cute cup of bubble tea smiling back at you, it doesn’t do anything when you toggle the options on the form yet.

Draw the image based on beverage size

The form has a segmented control which lets you choose between Regular or Large. Your job is to make the preview icon change size based on the selection.

Open BubbleTeaCup.swift, and replace its contents with the following code:

import UIKit
 
// 1
enum BeverageSize {
  case Regular, Large
}
 
@IBDesignable
class BubbleTeaCup: UIView {
  // 2
  var beverageSize: BeverageSize = .Regular {
    didSet {
      setNeedsDisplay()
    }
  }
  override func drawRect(rect: CGRect) {
    // 3
    let imageSize: CGRect
    switch beverageSize {
    case .Regular:
      imageSize = bounds.insetBy(dx: bounds.width * 0.1, dy: bounds.height * 0.1) // 4
    case .Large:
      imageSize = bounds // 5
    }
    // 6
    StyleKit.drawBubbleTeaCup(frame: imageSize)
  }
}

Let’s review this section by section:

  1. Creates an enum with beverage size options. This goes outside the class body so the rest of the app has access to it.
  2. Stores the state of the beverage size, which you’ll user later when calculating the image size. It also triggers a re-draw whenever this value changes.
  3. Calculates the image size based on the beverage size.
  4. Regular has a slightly smaller width and height.
  5. Large takes up the full view.
  6. Draws the image based on the imageSize dimensions.

When you set the beverageSize property, the view refreshes its display to reflect the new beverage size.

Wire up the segmented control

For this to actually work, you need to wire up the order form’s segmented control.

Open OrderViewController.swift and replace the sizeChange @IBAction method with the following:

@IBAction func sizeChange(sender: UISegmentedControl) {
  switch sender.selectedSegmentIndex {
  case 0:
    bubbleTeaCup.beverageSize = .Regular
  case 1:
    bubbleTeaCup.beverageSize = .Large
  default:
    break
  }
}

This sets the beverageSize property of the custom view based on the selectedSegmentIndex.

Build and run. Now when you toggle between Regular and Large, the order preview updates accordingly.

Toggle beverage size

Changing the tea color at runtime

PaintCode really shines when you have to change individual image layers at runtime. This would be a nightmare using PNGs.

In this section, you’re going to change the color of the tea based on flavor selection.

Pass in a parameter to change the color

By default, the PaintCode drawing methods expose parameters for size and stretch. In order to support color changes, you’ll need to add your own parameter.

Open StyleKit.swift and replace the following line of code:

class func drawBubbleTeaCup(frame frame: CGRect = CGRect(x: 0, y: 0, width: 161, height: 221), resizing: ResizingBehavior = .AspectFit) {

With the following:

class func drawBubbleTeaCup(frame frame: CGRect = CGRect(x: 0, y: 0, width: 161, height: 221), teaColor: UIColor = milkTea, resizing: ResizingBehavior = .AspectFit) {

You’re squeezing in an additional parameter teaColor into the method signature. You also have it default to milkTea so it doesn’t break existing code.

Next, scroll to around line 64 where the liquid layer color fill happens:

...
UIColor(hue: 0.078, saturation: 0.447, brightness: 0.843, alpha: 1).setFill() // change this
liquid.fill()
...

Replace the code so it looks like this:

...
teaColor.setFill() // now uses the parameter
liquid.fill()
...

Instead of filling the liquid with a hard-coded UIColor, you use the teaColor parameter instead.

Note: If you need to re-export the StyleKit file from Sketch, remember that your custom changes will be wiped out. If controlling layer behavior with custom parameters is something you’ll be doing often, consider using the full featured PaintCode 2 Mac app which has a neat Variables feature.

Wire up the custom view

The next step is to wire up the BubbleTeaCup class to use this new parameter.

Open BubbleTeaCup.swift, and add the following property above drawRect(_:):

var teaColor = StyleKit.milkTea {
  didSet {
    setNeedsDisplay()
  }
}

The teaColor property keeps track of the liquid color, and re-draws the view when it changes.

Within the same file, update the following line of code:

StyleKit.drawBubbleTeaCup(frame: imageSize)

To this:

StyleKit.drawBubbleTeaCup(frame: imageSize, teaColor: teaColor)

The canvas drawing method supports a new parameter, and you pass it the current teaColor.

Wire up the collection view

All of the bubble tea flavors are in a collection view at the bottom of the order tab. When a user taps a cell, you want the order preview image to change color too.

Open OrderViewController.swift and append the following line to the end of collectionView(_:didSelectItemAtIndexPath:indexPath:):

bubbleTeaCup.teaColor = selectedFlavor.color

selectedFlavor represents the Flavor object that the user tapped (i.e. Mango). Here you set the teaColor to the flavor’s color.

Build and run. Now when you choose different flavors, the order preview image updates as well.

Changing flavor colors

Hold the bubbles

Bubble tea sure has a lot of carbs! The drinks are sugary, and the bubbles are made of starchy tapioca balls. It’d be nice if there was a no-bubble option.

Pass in a parameter to change the color

In this section, you’re going to parameterize the image again. But this time, you’ll pass a flag to indicate whether or not to draw the bubbles.

Open StyleKit.swift and replace the following line of code:

class func drawBubbleTeaCup(frame frame: CGRect = CGRect(x: 0, y: 0, width: 161, height: 221), teaColor: UIColor = milkTea, resizing: ResizingBehavior = .AspectFit) {

With the following:

class func drawBubbleTeaCup(frame frame: CGRect = CGRect(x: 0, y: 0, width: 161, height: 221), teaColor: UIColor = milkTea, addBubbles: Bool = true, resizing: ResizingBehavior = .AspectFit) {

You’re inserting yet another parameter addBubbles with a default value of true.

Next, scroll to around line 157 toward the end of the bubble-related code. Replace the following line:

bubbles.fill()

With this:

if addBubbles {
  bubbles.fill()
}

You only draw the bubbles if the addBubbles parameter is true.

Wire up the custom view

Like before, the next step is to wire up the BubbleTeaCup class to use this new parameter.

Open BubbleTeaCup.swift, and add the following property below teaColor:

var bubbles = true {
  didSet {
    setNeedsDisplay()
  }
}

This is yet another property that triggers a re-draw when its value changes.

Within the same file, update the following line of code:

StyleKit.drawBubbleTeaCup(frame: imageSize, teaColor: teaColor)

To this:

StyleKit.drawBubbleTeaCup(frame: imageSize, teaColor: teaColor, addBubbles: bubbles)

Here, you pass the bubbles flag to the canvas drawing method.

Wire up the switch

All that’s left is to wire up the UISwitch in the order form.

Open OrderViewController.swift and replace the toggleBubbles @IBAction method with the following:

@IBAction func toggleBubbles(sender: UISwitch) {
  bubbleTeaCup.bubbles = sender.on
}

This updates the bubbles flag whenever the UISwitch is toggled.

Build and run. Now when you toggle the switch, the bubbles in the order preview image should disappear.

Toggles bubbles, flavor, and size

Pretty cool! Play around a bit and think back on all you’ve accomplished:

  • You’ve taken a cool illustration designed in Sketch…
  • …used the new PaintCode Sketch plugin to auto-generate Core Graphics code for that illustration…
  • …which results in smaller binary size, scalability, and the ability to dynamically customize the image at runtime!

Where To Go From Here?

You can download the final project which includes the Xcode project and Sketch file here.

To learn more about the PaintCode plugin, check out the tutorials on the official site.

If you need to dig deeper into Core Graphics, this tutorial is a good place to start. And if you don’t use Sketch but still like what the PaintCode plugin can do, consider whether PaintCode 2 is right for you.

We hope you enjoyed this tutorial, and if you have any questions or comments, please join the discussion below!

The post PaintCode Sketch Plugin Tutorial appeared first on Ray Wenderlich.


Viewing all articles
Browse latest Browse all 4399

Trending Articles