Ios Draw Circle in View

Update notation: Michael Katz updated this tutorial for iOS fourteen, Xcode 12 and Swift 5. Ray Wenderlich wrote the original.

Cadre Graphics is a powerful, yet friendly, set of APIs for drawing in a UIKit application. In add-on to primitives like shapes and gradients, with Core Graphics yous can code upwards patterns. Core Graphics Patterns are an arbitrary sets of graphics operations that can be tiled to make full an surface area. You can create magnificent backgrounds for your apps using repeated shapes. Core Graphics Patterns are a performant mode to scale a drawing to fill up whatever shape on the screen.

In this tutorial, you'll learn how to use Core Graphics to exercise the following:

  • Create a path-based drawing.
  • Draw a pattern.
  • Transform the pattern.
  • Utilize patterns to finish a design recognition game called Recall.

Note: If you're make new to Core Graphics, it would exist a good idea to review some of our entry-level tutorials on the topic. Consider working through the Lines, Rectangles, and Gradients and Arcs and Paths tutorials to get a better understanding of the foundations you'll build upon hither.

Getting Started

Commencement by clicking the Download Materials button at the peak or bottom of this tutorial. Build and run the starter app. Y'all'll see this (colors and letters may vary):

Starting version of Recall

Recall takes inspiration from a game in the Left vs Right brain preparation app. The goal of the game is to choose the most popular direction for objects in view. A new fix of objects displays in one case you make a option. You have 5 attempts before the game ends.

Recall groups pattern objects in four quadrants. Each quadrant in the starter app has a label. The text represents the direction and the background color represents the fill colour.

As a starting signal, the game is rather underwhelming. :[

Raze Face Not Impressed

Your chore is to use Cadre Graphics patterns to plow this pitiful app into the finished app below:

Final version of Recall

Look at the projection in Xcode. These are the main files:

  • GameViewController.swift: Controls the gameplay and displays the game view.
  • ResultViewController.swift: Displays the terminal score and a button to restart the game.
  • PatternView.swift: Displays the design view for one of the quadrants in the game view.

Toward the end of this tutorial, you'll raise PatternView to display the desired pattern.

For starters, you lot'll prototype your new and improved PatternView in a Playground. This allows yous to iterate much faster while learning the ins and outs of Core Graphics patterns. Once you're done, you'll transfer the relevant lawmaking over to the Remember starter project.

In Xcode, go to File ▸ New ▸ Playground…. Select the Single View template. Click Next, name the playground PatternView.playground, add it to the Recollect workspace and the Recall binder group and click Create. Your playground contains a view controller with a single view.

Note: If Xcode gives you lot an error trying to load the new program, the historic period-old "restart Xcode" should get you on your way.

Select Editor ▸ Run Playground to execute the playground. Click Show the Assistant Editor to display your starter view. It displays the iconic "How-do-you-do World!" upshot:

Hello world playground output

As you go through the side by side sections, you'll replace the starter view with your design view. Time to get started!

Agreement the Beefcake of a Pattern

In our previous Core Graphics tutorials, you've seen how to define and paint paths similar this:

two shape outlines, one white and one filled with yellow

A path is a set of instructions describing a shape. The example above shows you stroking the path on the left with a black line. The path on the right has been stroked with black and filled in with orange.

Using Core Graphics, you tin also stroke or fill a path with a blueprint. The case below shows a colored pattern filling out a path:

Drawing filled with pattern of colored squares

Setting up the Pattern

You set up a pattern by doing the following:

  1. Write a method that draws an individual design jail cell.
  2. Create a pattern with parameters that include how to describe and place an individual cell.
  3. Define the color information that your pattern will use.
  4. Paint the desired path with the blueprint y'all created.

Now, check out a slightly dissimilar blueprint cell with extra padding. The thin blackness border shows the bounds of the cell:

Pattern cell with blue, pink, green and red squares

You volition write a describe method that draws within the bounds of the cell. Core Graphics clips anything drawn outside the prison cell bounds. Core Graphics besides expects you to draw the pattern prison cell exactly the same way each time.

Your draw method tin can employ color when setting up your blueprint cell. This is a colored pattern. An uncolored or masking pattern is 1 where you apply the fill colour outside of the draw method. This gives you the flexibility to prepare up your blueprint colors where information technology makes sense.

Core Graphics calls your draw method repeatedly to gear up your blueprint. The pattern creation parameters define what the blueprint looks like. The example below shows a basic repeated pattern with the cells lining up correct next to each other:

Repeated pattern cell

You can specify the spacing between the pattern cells when you configure the pattern:

Repeated pattern cell with offset

Y'all can as well apply transformations to change the pattern's advent. The pictures beneath testify the pattern drawn inside a space represented past the fuzzy edge:

three variations of the repeated pattern cell

The first shows an unchanged pattern. In the second, you meet a translated blueprint. The third shows the pattern rotated. Again, the blackness border around the pattern cells highlights its bounds.

You take a lot of options bachelor when configuring a blueprint. You lot'll start putting all this together in the next department.

Creating the Pattern View

Add the post-obit code earlier the view controller class in PatternView.playground:

course PatternView: UIView {   override func draw(_ rect: CGRect) {     // i     guard let context = UIGraphicsGetCurrentContext()     else { return }     // 2     UIColor.orange.setFill()     // 3     context.fill(rect)   } }        

This represents the custom view for your design. Here, you override draw(_:) to practise the following:

  1. Get the view's graphics context.
  2. Fix the electric current fill color for the context.
  3. Fill the unabridged context with the current make full colour.

Think of the graphics context as a sheet you can draw on. The context contains data such as the color that will make full in or stroke a path. Yous can describe out paths in your canvas before painting them in with a context's colour data.

Inside MyViewController, replace the code in loadView() related to label with the post-obit:

allow patternView = PatternView() patternView.frame = CGRect(x: x, y: ten, width: 200, height: 200) view.addSubview(patternView)        

This creates an instance of the design view, sets its frame and adds information technology to view.

Press Shift-Control-Return to run the playground. The previous label is gone and replaced with an orangish subview:

Orange square in the top left corner

Coloring is just the first of the journey. You know in that location's more than where that came from!

Raze face bring it on

Cartoon a Blackness Circumvolve in the Pattern Prison cell

Add the following property inside the top of PatternView:

let drawPattern: CGPatternDrawPatternCallback = { _, context in   context.addArc(     middle: CGPoint(x: 20, y: xx),     radius: 10.0,     startAngle: 0,     endAngle: two.0 * .pi,     clockwise: false)   context.setFillColor(UIColor.black.cgColor)   context.fillPath() }        

The lawmaking above draws a circular path in the graphics context and fills it with black color.

This represents your blueprint prison cell'south drawing method, which is of the type CGPatternDrawPatternCallback. This is a closure with two arguments:

  1. A pointer to individual data associated with the pattern. You lot're not using individual information, and so you use an unnamed parameter here.
  2. The graphics context used in drawing your pattern cell.

Add together the post-obit code to the end of describe(_:):

var callbacks = CGPatternCallbacks(   version: 0,    drawPattern: drawPattern,    releaseInfo: nil)        

CGPatternCallbacks is a structure for belongings the callbacks used to draw a pattern. There are ii types of callback — one for the design, which you've made already, and one for cleaning upwardly and releasing any individual data, which you aren't using. You would typically prepare upwardly a release callback if you're using private data in the pattern. Since you don't apply individual data in your draw method, yous pass nil for this callback.

Creating the Pattern

To create the pattern, add the following correct after the code above:

guard let blueprint = CGPattern(   info: naught,   bounds: CGRect(x: 0, y: 0, width: 20, height: 20),   matrix: .identity,   xStep: 50,   yStep: fifty,   tiling: .constantSpacing,   isColored: truthful,   callbacks: &callbacks) else { return }        

This creates a pattern object. In the code to a higher place, y'all pass in the following parameters:

  • info: A pointer to whatsoever individual data you want to use in your pattern callbacks. You pass in nil here since you're not using any.
  • bounds: The pattern cell'south bounding box.
  • matrix: A matrix that represents the transform to apply. Y'all pass in the identity matrix, as you're non applying any transforms.
  • xStep: The horizontal spacing between pattern cells.
  • yStep: The vertical spacing betwixt blueprint cells.
  • tiling: The technique Cadre Graphics should use to business relationship for differences between user space units and device pixels.
  • isColored: Whether the blueprint prison cell draw method applies colour. You're setting this to truthful since your draw method sets a color.
  • callbacks: A pointer to the construction that holds the pattern callbacks.

Add the following lawmaking right after the blueprint assignment:

var alpha: CGFloat = 1.0 context.setFillPattern(design, colorComponents: &alpha) context.fill(rect)        

The code above sets the fill up pattern for the graphics context. For colored patterns, you must too pass in an alpha value to specify the pattern opacity. The pattern draw method provides the color. Finally, the code paints the view's frame area with the design.

Run the playground past pressing Shift-Command-Render. Your pattern isn't showing up. Foreign. What'south going on?

Setting the Blueprint'south Colour Infinite

You lot need to provide Core Graphics with information about your pattern'due south color space then it knows how to handle pattern colors. Colour space specifies how to interpret a colour value for brandish.

Add together the post-obit earlier the alpha declaration:

// 1 guard permit patternSpace = CGColorSpace(patternBaseSpace: nil) else { render } // 2 context.setFillColorSpace(patternSpace)        

Here'south what the code does:

  1. Create a pattern color space. The base space parameter should be nil for colored patterns. This delegates the coloring to your pattern jail cell draw method.
  2. Set the fill color space to your divers blueprint color space.

Run the playground. Yes! You should now encounter a circular blackness pattern:

Orange rectangle filled with black circle pattern

Side by side, you'll learn more about configuring patterns.

Configuring the Design

In your playground, change the spacing parameters that set upwards design as follows:

xStep: 30, yStep: 30,        

Run the playground. Note that the circular dots appear to be much closer to each other:

Orange rectangle filled with denser black circle pattern

This makes sense, as y'all've shrunk the stride size between pattern cells.

Now, change the spacing parameters as follows:

xStep: 20, yStep: 20,        

Run the playground. Your circles have turned into quarters:

Circles in pattern shown as quarters

Irresolute the Centers of the Circles

To empathise why, note that your draw method returns a circle with a radius of x centered at (twenty, 20). The blueprint's horizontal and vertical displacement is twenty. The cell's bounding box is 20×xx at origin (0,0). This results in a repeating quarter-circle that starts at the lower right border.

Change drawPattern that draws the circumvolve (context.addArc) to the post-obit:

context.addArc(   heart: CGPoint(10: 10, y: x),    radius: 10.0,   startAngle: 0,    endAngle: 2.0 * .pi,   clockwise: false)        

You've changed the eye point to be (ten, 10) rather than (twenty, 20).

Run the playground. You're back to whole circles due to the shift in the circle's middle:

Orange square filled with black circles touching each other

The pattern jail cell bounds as well match up perfectly with the circumvolve, resulting in each cell abutting the others.

Applying a Transformation to the Design

Y'all tin can transform your pattern in many interesting ways. Inside describe(_:), replace pattern with the following:

// 1 allow transform = CGAffineTransform(translationX: 5, y: 5) // 2 guard allow pattern = CGPattern(   info: nil,   premises: CGRect(x: 0, y: 0, width: 20, height: 20),   matrix: transform,   xStep: 20,   yStep: 20,   tiling: .constantSpacing,   isColored: true,   callbacks: &callbacks) else { return }        

You've modified the design by passing it a transformation matrix. Here's a closer look:

  1. Create an affine transformation matrix that represents a translation.
  2. Configure the pattern to use this transformation past passing it in matrix.

Run the playground. Note how the blueprint shifted to the right and downward to match the translation y'all divers:

Black circle pattern shifted right and down

Besides translating your pattern, you tin also scale and rotate the pattern cells. You'll encounter how to rotate the pattern later when yous build the pattern for the game app.

Adding Fill and Stroke to the Pattern

Here's how to fill up and stroke a colored pattern. In drawPattern replace the lines where you set the make full colour and fill up the path with the following:

context.setFillColor(UIColor.yellow.cgColor) context.setStrokeColor(UIColor.darkGray.cgColor) context.drawPath(using: .fillStroke)        

Here, you change the fill up color to yellow and fix the stroke color. You then call drawPath(using:) with the option that fills and strokes the path.

Run your playground and check that the pattern now shows your new fill color and stroke:

Yellow circles with black outlines on an orange background

Thus far, you've worked with colored patterns and defined the colors in the pattern describe method. In the finished game, you'll accept to create patterns with different colors. You probably realize that writing a depict method for each color isn't the style to go. This is where masking patterns come up into play.

Using Masking Patterns

Masking patterns define their color information outside the pattern cell draw method. This allows you to alter upward the pattern color to suit your needs.

Here's an example of a masking pattern that has no color associated with information technology:

Gray star image as a mask pattern

With the blueprint in place, you lot can at present apply color. The commencement example below shows a blue color applied to the mask, and the second displays an orange colour:

Star pattern in blue and orange

Now, you'll change the pattern yous've been working with to a masking pattern.

Delete the code from drawPattern where you set fill and stroke colors and draw the path and replace information technology with the following:

context.fillPath()        

This reverts the code back to filling the path.

Replace pattern with the post-obit:

guard allow pattern = CGPattern(   info: nil,   bounds: CGRect(10: 0, y: 0, width: twenty, summit: xx),   matrix: transform,   xStep: 25,   yStep: 25,   tiling: .constantSpacing,   isColored: false,   callbacks: &callbacks) else { return }        

This sets isColored to false, changing your pattern to a masking pattern. You've also increased the vertical and horizontal spacing to 25. Now, you lot need to provide the color space information for your pattern.

Replace the existing patternSpace consignment with the following:

let baseSpace = CGColorSpaceCreateDeviceRGB() baby-sit let patternSpace = CGColorSpace(patternBaseSpace: baseSpace) else { return }        

Here, you get a reference to a standard device-dependent RGB color infinite. You and so change your pattern color infinite to this value instead of the previous nil value.

Beneath that, supervene upon the lines where you create blastoff and prepare the context make full blueprint with the post-obit:

let fillColor: [CGFloat] = [0.0, 1.0, 1.0, 1.0] context.setFillPattern(pattern, colorComponents: fillColor)        

This creates a color applied underneath the mask when filling out the design.

Run the playground. Your pattern'south color updates to reflect the cyan color setting that you configured outside the depict method:

Cyan circle pattern on orange background

Stroking and Filling the Masking Pattern

Now, it's time to stroke and fill a masking design. It's like stroking a colored pattern.

Supersede the line context.fillPath() in drawPattern with the following:

context.setStrokeColor(UIColor.darkGray.cgColor) context.drawPath(using: .fillStroke)        

Although you gear up the stroke colour within draw(_:), your blueprint color is still set up outside the method.

Run the playground to run into the stroked pattern:

Cyan circle pattern on orange background

You've now congenital upward experience with dissimilar pattern configurations and with masking patterns. You lot can begin building out the pattern yous'll need for Recall.

Creating the Game Blueprint

Add the following lawmaking to the top of the playground:

extension CGPath {   // 1   static func triangle(in rect: CGRect) -> CGPath {     allow path = CGMutablePath()     // 2     let acme = CGPoint(x: rect.width / 2, y: 0)     let bottomLeft = CGPoint(10: 0, y: rect.height)     let bottomRight = CGPoint(x: rect.width, y: rect.height)     // 3     path.addLines(betwixt: [top, bottomLeft, bottomRight])     // iv     path.closeSubpath()     render path   } }        

Going through the code, step by step:

  1. Extend CGPath to create a triangular path.
  2. Specify the three points that brand up the triangle.
  3. Add lines between the points.
  4. Close the path.

Then inside PatternView, add the following empty enum:

enum Constants {   static let patternSize: CGFloat = 30.0   static permit patternRepeatCount: CGFloat = 2 }        

These represent the constants you lot'll use when setting up your pattern. patternSize defines the pattern cell size, and patternRepeatCount defines the number of pattern cells in the pattern view.

Drawing a Triangle

Add the following after the Constants definition:

let drawTriangle: CGPatternDrawPatternCallback = { _, context in   let trianglePath = CGPath.triangle(in:     CGRect(       x: 0,       y: 0,       width: Constants.patternSize,       height: Constants.patternSize))   context.addPath(trianglePath)   context.fillPath() }        

This defines a new callback for drawing your triangular pattern. In it, you call CGPath.triangle(in:) to return a path representing the triangle. Then you add together this path to the context before filling it.

Annotation that the closure doesn't specify a fill colour, so it tin can be a masking pattern.

In depict(_:), change callbacks to the post-obit:

var callbacks = CGPatternCallbacks(   version: 0,    drawPattern: drawTriangle,    releaseInfo: nil)        

You lot're now using the triangle drawing callback.

Drawing Repeating Triangles as a Pattern

Delete drawPattern, every bit it's no longer necessary. One can just go effectually in circles for so long. :]

Also, in draw(_:), replace the lawmaking that assigns transform and pattern with the following:

// i let patternStepX = rect.width / Constants.patternRepeatCount let patternStepY = rect.height / Constants.patternRepeatCount // two let patternOffsetX = (patternStepX - Constants.patternSize) / 2.0 allow patternOffsetY = (patternStepY - Constants.patternSize) / 2.0 // 3 let transform = CGAffineTransform(   translationX: patternOffsetX,   y: patternOffsetY) // four baby-sit let pattern = CGPattern(   info: nil,   bounds: CGRect(     x: 0,     y: 0,     width: Constants.patternSize,     height: Constants.patternSize),   matrix: transform,   xStep: patternStepX,   yStep: patternStepY,   tiling: .constantSpacing,   isColored: false,   callbacks: &callbacks) else { return }        

Here'southward what that code does, step by step:

  1. Calculate the horizontal and vertical footstep size using the view'south width and acme, every bit well as the number of pattern cells in a view.
  2. Work out the dimensions to horizontally and vertically heart a pattern cell within its premises.
  3. Ready up a CGAffineTransform translation based on the centering variables you defined.
  4. Create the pattern object based on your calculated parameters.

Run the playground. You lot volition run across four triangles, each centered both vertically and horizontally within their bounds:

Four cyan triangles pointing upward on an orange background

You lot'll side by side go your background colors to more than closely lucifer the Recall app.

In MyViewController, modify the groundwork color setup in loadView() as follows:

view.backgroundColor = .lightGray        

Next, go to PatternView and change the context make full setup in draw(_:) as follows:

UIColor.white.setFill()        

Run the playground. Your principal view's background should now be grey with a white background for your pattern view:

Four cyan triangles pointing upward on a white background

Customizing the Pattern View

At present that you have the basic pattern displaying correctly, y'all can make changes to control the pattern direction.

Add the following enumeration about the summit of PatternView after Constants:

enum PatternDirection: CaseIterable {   example left   case top   case right   instance bottom }        

This represents the different directions the triangle can point. They match the directions in your starter app.

Add the following properties to PatternView:

var fillColor: [CGFloat] = [one.0, 0.0, 0.0, ane.0] var direction: PatternDirection = .top        

This represents the color you'll apply to the masking pattern and the design direction. The class sets a default color of red (the iv array components represent red, green, blueish and blastoff) and the default direction of peak.

Delete the local fillColor declaration plant about the lesser of depict(_:). This will ensure that you employ the case property instead.

Supercede transform with the post-obit:

// 1 var transform: CGAffineTransform // 2 switch direction { case .top:   transform = .identity instance .right:   transform = CGAffineTransform(rotationAngle: 0.5 * .pi) case .bottom:   transform = CGAffineTransform(rotationAngle: .pi) case .left:   transform = CGAffineTransform(rotationAngle: 1.5 * .pi) } // 3 transform = transform.translatedBy(10: patternOffsetX, y: patternOffsetY)        

Hither's what just happened:

  1. Declare a CGAffineTransform variable for your blueprint transform.
  2. Assign the transform to the identity matrix if the pattern management is top. Otherwise, the transform is a rotation based on the direction. For example, if the pattern points right, then the rotation is π / 2 radians or 90º clockwise.
  3. Apply a CGAffineTransform translation to center the pattern jail cell within its bounds.

Run the playground. Your triangles are red, based on your default pattern fill color:

Four red triangles pointing upward on a white background

Changing the Pattern'south Color and Direction

Now's a corking time to set up upwards code to command and examination the design colour and direction.

Add the post-obit methods in PatternView subsequently the property definitions:

init(fillColor: [CGFloat], management: PatternDirection = .tiptop) {   self.fillColor = fillColor   self.direction = direction   super.init(frame: CGRect.nil) }    required init?(coder aDecoder: NSCoder) {   super.init(coder: aDecoder) }        

This sets up an initializer that takes in a fill color and a pattern management. direction has a default value.

You've also added the required initializer for when a storyboard initializes the view. You'll need this later when yous transfer your code to the app.

In MyViewController, change patternView since you've changed the initializer:

let patternView = PatternView(   fillColor: [0.0, one.0, 0.0, i.0],   management: .right)        

Here, you instantiate a pattern view with not-default values.

Run the playground. Your triangles are at present green and pointing to the correct:

Green triangles pointing to the right on a white background

Congratulations! You're washed prototyping your blueprint using Playgrounds. It's time to utilize this blueprint in Call up.

Updating the Game to Use the Pattern

Open up the Retrieve starter projection. Become to PatternView.swift and copy over the CGPath extension from your playground to the end of the file.

Next, supervene upon PatternView in PatternView.swift with the class from your playground.


Note
: You lot can vastly simplify this procedure by using Xcode'due south code folding feature. In the playground, put the cursor just after the opening caryatid of class PatternView: UIView { and select Editor ▸ Code Folding ▸ Fold from the card. Triple-click the resulting folded line to select the unabridged course and printing Command-C. In the project, echo the process to fold and select the course. Press Control-Five to replace it.

Build and run the app. You lot should see something like this:

Pattern with all red triangles pointing upward

Something'due south non quite right. Your pattern appears to be stuck in default mode. It looks like a new game view isn't refreshing the pattern views.

Go to GameViewController.swift and add together the following to the end of setupPatternView(_:towards:havingColor:):

patternView.setNeedsDisplay()        

This prompts the system to redraw the pattern so that it picks upward the new pattern data.

Build and run the app. Y'all should at present run into colors and directions nicely mixed up:

Triangles of various colors pointing in different directions

Tap one of the respond buttons and play through the game to cheque that everything works as expected.

Congratulations on completing Recall! Yous've come a long fashion from the mind-numbing days of simple pigment jobs.

Raze face paint ninja

Considering Performance When Using Patterns

Core Graphics patterns are really fast. Here are several options you can use to describe patterns:

  1. Using the Core Graphics design APIs that you worked through in this tutorial.
  2. Using UIKit wrapper methods such as UIColor(patternImage:).
  3. Drawing the desired pattern in a loop with many Core Graphics calls.

If your pattern is but fatigued once, the UIKit wrapper method is the easiest. Its performance should also be comparable to the lower-level Core Graphics calls. An instance of when to utilize this is to pigment a static groundwork pattern.

Core Graphics can work in a groundwork thread, unlike UIKit, which runs on the chief thread. Core Graphics patterns are more performant with complicated drawings or dynamic patterns.

Drawing the pattern in a loop is the slowest pick. A Core Graphics blueprint makes the draw call once and caches the results, making information technology more efficient.

Where to Go From Here?

Access the final project by clicking the Download Materials push at the top or bottom of this tutorial. Y'all can besides use this to cheque your piece of work if you get stuck.

Yous should at present have a solid agreement of how to use Core Graphics to create patterns. Check out the Patterns and Playgrounds tutorial to learn how to build patterns using UIKit.

You may too want to read through the Curves and Layers tutorial, which focuses on drawing various curves and cloning them using layers.

Nosotros hope you enjoyed this tutorial. If you take any comments or questions, please join the forum give-and-take below!

welchvilven.blogspot.com

Source: https://www.raywenderlich.com/21462527-core-graphics-tutorial-patterns

0 Response to "Ios Draw Circle in View"

Enviar um comentário

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel