Drawing in iOS with SwiftUI | raywenderlich.com

Learn about drawing using SwiftUI by creating custom controls using a combination of SwiftUI and Core Graphics. Covers shapes, colors, drawing with Pencil, and how to integrate them into a non-trivial app.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/6485147-drawing-in-ios-with-swiftui
1 Like

Love this course and highly recommended. You will always learn a lot with Caroline as instructor.

2 Likes

Hello,
I had a question about a previous tutorial you did (years ago). It dealt with your “How To Make a Letter / Word Game with UIKit and Swift: Part 1/3” tutorial.
In the app, you used an image for your tiles. I am curious how it would be possible to draw a square or rectangle around the letters using CGRect instead. I am trying with no success.
Again, don’t mean to bring up a question in another tutorial but I didn’t know any other way to contact you.
Thanks!

If you subclass a UIView, you can override draw(_:_) .

Within that method you’ll have a rect with the size of the view and you can draw into that rect.

override func draw(_ rect: CGRect) {
  // Method 1
  let context = UIGraphicsGetCurrentContext()
  context?.setFillColor(UIColor.green.cgColor)
  context?.fill(rect)

  // Method 2
  let path = UIBezierPath(rect: rect.inset(by: UIEdgeInsets(top: 30, left: 30, bottom: 30, right: 30)))
  UIColor.red.setFill()
  path.fill()
}

This video course: https://www.raywenderlich.com/4659-drawing-in-ios-with-core-animation-and-core-graphics should help!

Or this tutorial: https://www.raywenderlich.com/411-core-graphics-tutorial-part-1-getting-started

Thank you very much!
I really appreciate it :slight_smile:

1 Like

Thank you Caroline,

I loved this training. Is there any way I can get in touch with you about ways that this could be extended to address how to serialize these mind maps in to documents (UIDocument, Codable, and iCloud)

Scott

There’s a tutorial on UIDocument: https://www.raywenderlich.com/1809473-uidocument-from-scratch

A video course on saving data: https://www.raywenderlich.com/5429634-saving-data-in-ios - this includes JSON and Codable

If you have a subscription, you should also have access to our books. UIKit Apprentice talks about saving and loading.

I’ve sent you a PM too :slight_smile:

I am working through this course using Xcode 12.5 & IOS 14.5 (Simulator) and I am having a problem in chapter 2-16 with the onTapgesture at line 95 in file ShapeGridView.swift:
even with the provided P02E06 Install Custom Menu end project I am not able to get this piece of code running.
Was there a change preventing this code to run as shown in the video?

Hi @hjm

Good question!. The shape needs a background color to tap on. Currently there is a stroke around the edge of the shape, so if you tap the edge of the shape, then it works. The center doesn’t have anything to tap!

In ShapesGridView.swift, in ShapesGrid, I would suggest replacing this code at the top of the ForEach in body:

self.finalArray[rowIndex][columnIndex].shape
.stroke()

with:

let shape =
  self.finalArray[rowIndex][columnIndex].shape
  shape
  .stroke()
  .background(
    Color.white
    .clipShape(shape)
  )
 // then it continues with .frame...

This will give the shape a background color of white (try red first so you can see what happens when you clip), and clip it to the same shape.

Thank you.
Now I have encountered another issue:
Performing a device rotation while having the ShapeGridView visible results in a crash because the ForEach Loops are expecting constants and by rotating the device the number of rows and columns are no longer constant.
Here is the exact log:

ForEach<Range, Int, ModifiedContent<HStack<ForEach<Range, Int, ModifiedContent<ModifiedContent<ModifiedContent<ModifiedContent<_StrokedShape, _BackgroundModifier>, _FrameLayout>, _PaddingLayout>, AddGestureModifier<_EndedGesture>>>>, _FrameLayout>> count (1) != its initial count (2). ForEach(_:content:) should only be used for constant data. Instead conform data to Identifiable or use ForEach(_:id:content:) and provide an explicit id!

ForEach<Range, Int, ModifiedContent<ModifiedContent<ModifiedContent<ModifiedContent<_StrokedShape, _BackgroundModifier>, _FrameLayout>, _PaddingLayout>, AddGestureModifier<_EndedGesture>>> count (7) != its initial count (3). ForEach(_:content:) should only be used for constant data. Instead conform data to Identifiable or use ForEach(_:id:content:) and provide an explicit id!

Swift/ContiguousArrayBuffer.swift:580: Fatal error: Index out of range

Resolved the orientation change issue:
(1)made ShapeType Identifiable
extension ShapeType: Identifiable {
var id: ShapeType { self }
}
(2) added in both ForEach statements in ShapeGridView.swift an additional parameter id: \.self

        ForEach(0..<finalArray.count,  id: \.self) { rowIndex in
            HStack (spacing: 0 ) {
                ForEach ( 0..<self.finalArray[rowIndex].count, id: \.self) { columnIndex in .....

Now I can rotate the device without crash when the ShapeGridView is opened

1 Like

Excellent - thank you so much for reporting back!