All Projects → powermobileweb → ForceSketch

powermobileweb / ForceSketch

Licence: other
Demonstration of a Sketching App Using 3D Touch

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to ForceSketch

Sketchcrapp
SketchCrapp - Crack your Sketch.app in seconds :) Supports MacOS Big Sur.
Stars: ✭ 218 (+1111.11%)
Mutual labels:  sketch
Weui Design
Design package for WeUI
Stars: ✭ 2,758 (+15222.22%)
Mutual labels:  sketch
sketch-data
Various lists to use as data source in Sketch app and other design applications
Stars: ✭ 151 (+738.89%)
Mutual labels:  sketch
Git Sketch Plugin
💎 A Git client generating pretty diffs built right into Sketch.
Stars: ✭ 2,459 (+13561.11%)
Mutual labels:  sketch
Sketch Feather
Sketch library for Feather icons
Stars: ✭ 237 (+1216.67%)
Mutual labels:  sketch
React Sketchapp
render React components to Sketch ⚛️💎
Stars: ✭ 14,861 (+82461.11%)
Mutual labels:  sketch
Plugin Requests
A collection of plugins requested to our Twitter account
Stars: ✭ 211 (+1072.22%)
Mutual labels:  sketch
Components-for-Sketch
A collection of Sketch files I've constructed for use in various projects. More coming soon and on a regular basis.
Stars: ✭ 23 (+27.78%)
Mutual labels:  sketch
Sketchsheets
Free ready to print sketch sheet templates for UX designers
Stars: ✭ 241 (+1238.89%)
Mutual labels:  sketch
SwiftyJot
Use your finger to annotate images.
Stars: ✭ 14 (-22.22%)
Mutual labels:  iphone
Miaow
A set of plugins for Sketch include drawing links & marks, UI Kit & Color sync, font & text replacing.
Stars: ✭ 2,536 (+13988.89%)
Mutual labels:  sketch
Pdf Export Sketch Plugin
Sketch plugin for PDF exporting
Stars: ✭ 231 (+1183.33%)
Mutual labels:  sketch
haoshiyou-client
Source code for haoshiyou clients (Hybrid HTML5 App)
Stars: ✭ 14 (-22.22%)
Mutual labels:  iphone
Tinyfaces Sketch Plugin
Fill selected layers in Sketch with free stock avatars
Stars: ✭ 221 (+1127.78%)
Mutual labels:  sketch
Shukofukurou-iOS
The Ultimate Open Source AniList, Kitsu, and MyAnimeList Tracker for iOS/iPadOS written in Objective-C
Stars: ✭ 29 (+61.11%)
Mutual labels:  iphone
Fluid For Sketch
[Sketch Plugin] Sketch-flavored Auto Layout-like Constraints
Stars: ✭ 2,408 (+13277.78%)
Mutual labels:  sketch
Sketchtoswift
📲 Generate Swift from Sketch
Stars: ✭ 251 (+1294.44%)
Mutual labels:  sketch
AppLibraryController
App Library Controller - Control App Library
Stars: ✭ 14 (-22.22%)
Mutual labels:  iphone
typex
Typography web export (css, sass, html, json, ..) plugin for Sketch
Stars: ✭ 42 (+133.33%)
Mutual labels:  sketch
SignTools-CI
Sign iOS apps on demand using CI. Part of: https://github.com/SignTools/SignTools
Stars: ✭ 145 (+705.56%)
Mutual labels:  iphone

ForceSketch

####Demonstration of a Sketching App Using 3D Touch

screenshot

#####Companion project to this blog post: http://flexmonkey.blogspot.co.uk/2015/10/forcesketch-3d-touch-drawing-app-using.html

Following on from my recent posts on 3D Touch and touch coalescing, combining the two things together in a simple drawing application seemed like an obvious next step. This also gives me the chance to tinker with CIImageAccumulator which was newly introduced in iOS 9.

My little demo app, ForceSketch, allows the user to draw on their iPhone 6 screen. Both the line weight and the line colour are linked to the touch pressure. Much like my ChromaTouch demo, the pressure controls the hue, so the very lightest touch is red, turning to green at a third of maximum pressure, to blue at two thirds and back to red at maximum pressure.

Once the user lifts their finger, two Core Image filters, CIColorControls and CIGaussianBlur kick in and fade the drawing out.

##Drawing Mechanics of ForceSketch

The drawing code is all called from my view controller's touchesMoved method. It's in here that I create a UIImage instance based on the coalesced touches and composite that image overthe existing image accumulator. In a production application, I'd probably do the image filtering in a background thread to improve the performance of the user interface but, for this demo, I think this approach is OK.

The opening guard statement ensures I have non-optional constants for the most important items:

    guard let touch = touches.first,
        event = event,
        coalescedTouches = event.coalescedTouchesForTouch(touch) else
    {
        return
    }

The next step is to prepare for creating the image object. To do this, I need to begin an image context and create a reference to the current context:

    UIGraphicsBeginImageContext(view.frame.size)

    let cgContext = UIGraphicsGetCurrentContext()

To ensure I get maximum fidelity of the user's gesture, I loop over the coalesced touches - this gives me all the intermediate touches that may have happened between invocations of touchesMoved().

    for coalescedTouch in coalescedTouches {

Using the force property of each touch, I create constants for the line segments colour and weight. To ensure users of non-3D Touch devices call still use the app, I check forceTouchCapability and give those users a fixed weight and colour:

    let lineWidth = (traitCollection.forceTouchCapability == UIForceTouchCapability.Available) ?
        (coalescedTouch.force / coalescedTouch.maximumPossibleForce) * 20 :
        10
    
    let lineColor = (traitCollection.forceTouchCapability == UIForceTouchCapability.Available) ?
        UIColor(hue: coalescedTouch.force / coalescedTouch.maximumPossibleForce, saturation: 1, brightness: 1, alpha: 1).CGColor :
        UIColor.grayColor().CGColor

With these constants I can set the line width and stroke colour in the graphics context:

    CGContextSetLineWidth(cgContext, lineWidth)
    CGContextSetStrokeColorWithColor(cgContext, lineColor)

...and I'm now ready to define the beginning and end of my line segment for this coalesced touch:

    CGContextMoveToPoint(cgContext,
        previousTouchLocation!.x,
        previousTouchLocation!.y)

    CGContextAddLineToPoint(cgContext,
        coalescedTouch.locationInView(view).x,
        coalescedTouch.locationInView(view).y)

The final steps inside the coalesced touches loop is to stroke the path and update previousTouchLocation:

    CGContextStrokePath(cgContext)

    previousTouchLocation = coalescedTouch.locationInView(view)

Once all of the strokes have been added to the graphics context, it's one line of code to create a UIImage instance and then end the context:

    let drawnImage = UIGraphicsGetImageFromCurrentImageContext()

    UIGraphicsEndImageContext()

##Displaying the Drawn Lines

To display the newly drawn lines held in drawnImage, I use a CISourceOverCompositing filter with drawnImage as the foreground image and the image accumulator's current image as the background:

    compositeFilter.setValue(CIImage(image: drawnImage),
        forKey: kCIInputImageKey)
        
    compositeFilter.setValue(imageAccumulator.image(),
        forKey: kCIInputBackgroundImageKey)

Then take the output of the source over compositor, pass that back into the accumulator and populate my UIImageView with the accumulator's image:

    imageAccumulator.setImage(compositeFilter.valueForKey(kCIOutputImageKey) as! CIImage)

    imageView.image = UIImage(CIImage: imageAccumulator.image())

##Blurry Fade Out

Once the user lifts their finger, I do a "blurry fade out" of the drawn image. This effect uses two Core Image filters which are defined as constants:

    let hsb = CIFilter(name: "CIColorControls",
        withInputParameters: [kCIInputBrightnessKey: 0.05])!
    let gaussianBlur = CIFilter(name: "CIGaussianBlur",
        withInputParameters: [kCIInputRadiusKey: 1])!

The first part of the effect is to use a CADisplayLink which will invoke step() with each screen refresh:

    let displayLink = CADisplayLink(target: self, selector: Selector("step"))
    displayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSDefaultRunLoopMode)

I rely on previousTouchLocation being nil to infer the user has finished their touch. If that's the case, I simply pass the accumulator's current image into the HSB / colour control filter, pass that filter's output into the Gaussian Blur and finally the blur's output back into the accumulator:

    hsb.setValue(imageAccumulator.image(), forKey: kCIInputImageKey)
    gaussianBlur.setValue(hsb.valueForKey(kCIOutputImageKey) as! CIImage, forKey: kCIInputImageKey)
    
    imageAccumulator.setImage(gaussianBlur.valueForKey(kCIOutputImageKey) as! CIImage)

    imageView.image = UIImage(CIImage: imageAccumulator.image())

##Source Code

As always, the source code for this project is available in my GitHub repository here. Enjoy! PowerMobileWeb

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].