{"id":18839761,"url":"https://github.com/maximbilan/ios-swift-drawing-app","last_synced_at":"2025-06-24T06:08:21.583Z","repository":{"id":31179096,"uuid":"34739579","full_name":"maximbilan/iOS-Swift-Drawing-App","owner":"maximbilan","description":"Swift Drawing Application Sample","archived":false,"fork":false,"pushed_at":"2018-09-22T07:12:34.000Z","size":70,"stargazers_count":43,"open_issues_count":0,"forks_count":7,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-21T07:20:49.638Z","etag":null,"topics":["drawing-application","ios","swift","tutorial","uiimage"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maximbilan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-04-28T15:40:06.000Z","updated_at":"2025-03-26T17:22:58.000Z","dependencies_parsed_at":"2022-09-13T17:22:33.068Z","dependency_job_id":null,"html_url":"https://github.com/maximbilan/iOS-Swift-Drawing-App","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/maximbilan/iOS-Swift-Drawing-App","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maximbilan%2FiOS-Swift-Drawing-App","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maximbilan%2FiOS-Swift-Drawing-App/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maximbilan%2FiOS-Swift-Drawing-App/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maximbilan%2FiOS-Swift-Drawing-App/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maximbilan","download_url":"https://codeload.github.com/maximbilan/iOS-Swift-Drawing-App/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maximbilan%2FiOS-Swift-Drawing-App/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261618130,"owners_count":23185095,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["drawing-application","ios","swift","tutorial","uiimage"],"created_at":"2024-11-08T02:44:00.377Z","updated_at":"2025-06-24T06:08:21.563Z","avatar_url":"https://github.com/maximbilan.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch4\u003eiOS Swift Drawing Application Sample\u003c/h4\u003e\n\nA simple example which describes how to draw in the \u003ci\u003eUIView\u003c/i\u003e using \u003ci\u003eSwift\u003c/i\u003e programming language.\nWe need to create the class \u003ci\u003eDrawingView\u003c/i\u003e inherited from \u003ci\u003eUIView\u003c/i\u003e. With the following properties:\n\u003cpre\u003e\nvar drawColor = UIColor.blackColor()\t// A color for drawing\nvar lineWidth: CGFloat = 5\t\t// A line width\n\t\nprivate var lastPoint: CGPoint!\t\t// A point for storing the last position\nprivate var bezierPath: UIBezierPath!\t// A bezier path\nprivate var pointCounter: Int = 0\t// A counter of ponts\nprivate let pointLimit: Int = 128\t// A limit of points\nprivate var preRenderImage: UIImage!\t// A pre-render image\n\u003c/pre\u003e\n\nFirst of all, initialization. We need to create \u003ci\u003eUIBezierPath\u003c/i\u003e and set up some properties.\n\n\u003cpre\u003e\noverride init(frame: CGRect) {\n\tsuper.init(frame: frame)\n\t\t\n\tinitBezierPath()\n}\n\nrequired init(coder aDecoder: NSCoder) {\n\tsuper.init(coder: aDecoder)\n\t\t\n\tinitBezierPath()\n}\n\t\nfunc initBezierPath() {\n\tbezierPath = UIBezierPath()\n\tbezierPath.lineCapStyle = kCGLineCapRound\n\tbezierPath.lineJoinStyle = kCGLineJoinRound\n}\n\u003c/pre\u003e\n\nFor better performance we will store the bezier path rendering to \u003ci\u003eUIImage\u003c/i\u003e, so create the function \u003ci\u003erenderToImage\u003c/i\u003e.\n\u003cpre\u003e\nfunc renderToImage() {\n\t\t\n\tUIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0.0)\n\tif preRenderImage != nil {\n\t\tpreRenderImage.drawInRect(self.bounds)\n\t}\n\t\t\n\tbezierPath.lineWidth = lineWidth\n\tdrawColor.setFill()\n\tdrawColor.setStroke()\n\tbezierPath.stroke()\n\t\t\n\tpreRenderImage = UIGraphicsGetImageFromCurrentImageContext()\n\t\t\n\tUIGraphicsEndImageContext()\n}\n\u003c/pre\u003e\n\nAnd implement the rendering function.\n\u003cpre\u003e\noverride func drawRect(rect: CGRect) {\n\tsuper.drawRect(rect)\n\t\t\n\tif preRenderImage != nil {\n\t\tpreRenderImage.drawInRect(self.bounds)\n\t}\n\t\t\n\tbezierPath.lineWidth = lineWidth\n\tdrawColor.setFill()\n\tdrawColor.setStroke()\n\tbezierPath.stroke()\n}\n\u003c/pre\u003e\n\nFirst, draw the pre-render image and after that render the current bezier path.\u003cbr\u003e\nNow, main of our application, it's touch handling.\n\nIn \u003ci\u003etouchesBegan\u003c/i\u003e function we save the last point and reset the point counter.\n\n\u003cpre\u003e\noverride func touchesBegan(touches: Set\u003cNSObject\u003e, withEvent event: UIEvent) {\n\tlet touch: AnyObject? = touches.first\n\tlastPoint = touch!.locationInView(self)\n\tpointCounter = 0\n}\n\u003c/pre\u003e\n\nIn \u003ci\u003etouchesMoved\u003c/i\u003e function, add a point to the bezier path, increment the point counter and if the point counter equals a point limit, than render the bezier path to \u003ci\u003eUIImage\u003c/i\u003e and reset the bezier path. And update the screen.\n\n\u003cpre\u003e\noverride func touchesMoved(touches: Set\u003cNSObject\u003e, withEvent event: UIEvent) {\n\tlet touch: AnyObject? = touches.first\n\tvar newPoint = touch!.locationInView(self)\n\t\t\n\tbezierPath.moveToPoint(lastPoint)\n\tbezierPath.addLineToPoint(newPoint)\n\tlastPoint = newPoint\n\t\t\n\t++pointCounter\n\t\t\n\tif pointCounter == pointLimit {\n\t\tpointCounter = 0\n\t\trenderToImage()\n\t\tsetNeedsDisplay()\n\t\tbezierPath.removeAllPoints()\n\t}\n\telse {\n\t\tsetNeedsDisplay()\n\t}\n}\n\u003c/pre\u003e\n\nIn \u003ci\u003etouchesEnded\u003c/i\u003e function reset the pointer counter, render the bezier path to \u003ci\u003eUIImage\u003c/i\u003e, reset the bezier path and update the screen.\n\n\u003cpre\u003e\noverride func touchesEnded(touches: Set\u003cNSObject\u003e, withEvent event: UIEvent) {\n\tpointCounter = 0\n\trenderToImage()\n\tsetNeedsDisplay()\n\tbezierPath.removeAllPoints()\n}\n\u003c/pre\u003e\n\nIn \u003ci\u003etouchesCancelled\u003c/i\u003e function just call \u003ci\u003etouchesEnded\u003c/i\u003e.\n\n\u003cpre\u003e\noverride func touchesCancelled(touches: Set\u003cNSObject\u003e!, withEvent event: UIEvent!) {\n\ttouchesEnded(touches, withEvent: event)\n}\n\u003c/pre\u003e\n\nFor clearing the view we need remove all points from the bezier path, reset the pre-render image and update the display:\n\n\u003cpre\u003e\nfunc clear() {\n\tpreRenderImage = nil\n\tbezierPath.removeAllPoints()\n\tsetNeedsDisplay()\n}\n\u003c/pre\u003e\n\nAnd for checking lines on the view:\n\n\u003cpre\u003e\nfunc hasLines() -\u003e Bool {\n\treturn preRenderImage != nil || !bezierPath.empty\n}\n\u003c/pre\u003e\n\nThat's all and we have really simple drawing application written by \u003ci\u003eSwift\u003c/i\u003e.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaximbilan%2Fios-swift-drawing-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaximbilan%2Fios-swift-drawing-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaximbilan%2Fios-swift-drawing-app/lists"}