Supporting SwiftUI with Core Graphics

Nov 22 2022 · Swift 5.5, iOS 15, Xcode 13

Part 1: Supporting SwiftUI with Core Graphics

06. Shading with Pencil

Episode complete

Play next episode

Next
About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 05. Drawing with Pencil Next episode: 07. Create a Thumbnail

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Heads up... You've reached locked video content where the transcript will be shown as obfuscated text.

Azimuth & Altitude

As well as detecting force and giving us coalesced touches, Pencil is able to give us the tilt in three dimensions. Using this tilt information, we can shade instead of just draw.

Assets

When we shade, instead of drawing a stroke, we’re going to draw a image that looks like a pencil shading.

CanvasView.swift

In CanvasView, right under the color property, add a shading color property that sets up the pencil texture as a UImage with the correct color.

var shadingColor: UIColor = .black {
  didSet {
    let image = UIImage(named: "pencilTexture")!
  }
}
let tintedImage = UIGraphicsImageRenderer(size: image.size).image { _ in
  color.set()
  image.draw(at: .zero)
}
shadingColor = UIColor(patternImage: tintedImage)
var color: UIColor = .black {
  didSet {
    shadingColor = color
  }
}
shadingColor.setStroke()
private let tiltThreshold: CGFloat = .pi / 6
if touch.altitudeAngle < tiltThreshold {
  shadingColor.setStroke()
} else {
  if touch.force > 0 {
    lineWidth = touch.force * forceSensitivity
  }
  color.setStroke()
}
private func lineWidthForShading(touch: UITouch) -> CGFloat {
  
}
let maxLineWidth: CGFloat = 60
let minAltitudeAngle: CGFloat = 0.25
let maxAltitudeAngle = tiltThreshold
let altitudeAngle = max(minAltitudeAngle, touch.altitudeAngle)
let normalizedAltitude = (altitudeAngle - minAltitudeAngle) / (maxAltitudeAngle - minAltitudeAngle)
return max(maxLineWidth * (1 - normalizedAltitude), minLineWidth)
🟩var lineWidth: CGFloat

if touch.altitudeAngle < tiltThreshold {
  🟩lineWidth = lineWidthForShading(touch: touch)
  ...
} else {
  🟩lineWidth = defaultLineWidth
  ...
}
let minForce: CGFloat = 0
let maxForce: CGFloat = 4
let normalizedAlpha = (touch.force - minForce) / (maxForce - minForce)
context.setAlpha(normalizedAlpha)