Demonstration of a Sketching App Using 3D Touch

Related tags

Charts ForceSketch
Overview

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!

You might also like...
Repositório com o app exemplo para o uso do gráfico radar.
Repositório com o app exemplo para o uso do gráfico radar.

RadarExample Repositório com o app exemplo para o uso do gráfico radar. É um método gráfico de apresentar dados multivariáveis, na forma de um gráfico

Integrate beautiful minimalistic plots into your app.

PlotUI · Integrate beautiful minimalistic plots into your app. Installation You can use PlotUI as package dependency to your app using Xcode: github.c

Demonstration of using UIWindowScene and SwiftUI to provide a native-looking Mac preferences window in Catalyst
Demonstration of using UIWindowScene and SwiftUI to provide a native-looking Mac preferences window in Catalyst

CatalystPrefsWindow Ever wondered how to create a more Mac-like preferences window for Catalyst? Perhaps Settings Bundles are too limiting for the kin

Demonstration library for using the Secure Enclave on iOS
Demonstration library for using the Secure Enclave on iOS

SecureEnclaveCrypto This project shows you how to create a keypair where as the private key is stored in the secure enclave sign a string / some data

Demonstration of using Tasks and TaskGroup to thread a calculation.

TasksTest Demonstration of using Tasks and TaskGroup to thread a calculation. The calculation takes place in a separate Swift class that can be reused

Demonstration of how to integrate AppleScript/Cocoa scripting into a Catalyst app
Demonstration of how to integrate AppleScript/Cocoa scripting into a Catalyst app

CatalystAppleScript Trivial demonstration showing how to build support for AppleScript into a Catalyst app. Showcases multiple commands and variables

Valorem-demo - Demonstration code and video of Valorem, a bespoke portfolio recommendation platform to be created as an iOS mobile app.

valorem-demo Demonstration code of Valorem, a bespoke portfolio recommendation platform to be created as an iOS mobile app. The included code demonstr

Demonstration blackjack app for native iOS. Uses MVVM architecture
Demonstration blackjack app for native iOS. Uses MVVM architecture

Blackjack - native iOS application This project is a simple demonstration on how to intergrate swiftUI with MVVM architecture. Although, technically,

A demonstration for bridging between Combine and your new async functions

CombineAsyncually This is a DEMONSTRATION of how you can bridge the new async / await functionality in Swift 5.5 with Combine. There is NO WARRANTY. T

A demonstration to the approach of leaving view transition management to a router.
A demonstration to the approach of leaving view transition management to a router.

SwiftUI-RouterDemo This is a simplified demonstration to the approach of leaving view transition management to a router.

Demonstration code for a simple Swift property-wrapper, keypath-based dependency injection system. The keypaths ensure compile-time safety for all injectable services.

Injectable Demo Preliminary musings and demonstration code for a simple Swift property-wrapper, keypath-based dependency injection system. The keypath

Demonstration of LegoArtFilter for iOS/macOS
Demonstration of LegoArtFilter for iOS/macOS

LegoArtFilterDemo Demonstration of LegoArtFilter for iOS/macOS. This project runs on both iOS (14≤) and macOS (11≤). Libraries LegoColors LegoArtFilte

Water Ripple Animation Demonstration
Water Ripple Animation Demonstration

WaterRippleAnimationDemonstration Water Ripple Animation Demonstration From the

Demonstration of Cocoapod test targets failing to build when integrated with TestingExtensions 0.2.11.

TestingExtensions0_2_11-Bug Symptoms Open project, hit test (Command+U), TestingExtensions fails to compile with a list of errors appearing to be rela

TestSchedulerDemo - Demonstration code for iOS Unit Tests and Asynchronous

TestSchedulerDemo This repository contains demonstration code for my Medium arti

SecretSquirrel: A Demonstration of releasing Closed Source libraries privately via SPM
SecretSquirrel: A Demonstration of releasing Closed Source libraries privately via SPM

SecretSquirrel: A Demonstration of releasing Closed Source libraries privately via SPM. A demo repository that showcases how to properly vend a closed

CTPanoramaView is a library that displays spherical or cylindrical panoramas with touch or motion based controls.
CTPanoramaView is a library that displays spherical or cylindrical panoramas with touch or motion based controls.

CTPanoramaView is a high-performance library that uses SceneKit to display complete spherical or cylindrical panoramas with touch or motion based controls.

Realtime Dynamic localization translation delivery system for iOS and Mac OSX in Swift. Create and update texts from localization.com without needing to recompile or redeploy. Cocapod for iOS devices (iPad, iPhone, iPod Touch and Mac) SAHistoryNavigationViewController realizes iOS task manager like UI in UINavigationContoller. Support 3D Touch!
SAHistoryNavigationViewController realizes iOS task manager like UI in UINavigationContoller. Support 3D Touch!

SAHistoryNavigationViewController Support 3D Touch for iOS9!! SAHistoryNavigationViewController realizes iOS task manager like UI in UINavigationConto

Comments
Owner
simon gladman
simon gladman
Repository with example app for using Bar chart

Gráfico de Barras (Exemplo) Repositório com app exemplo para o uso do gráfico de Barras. O gráfico de barras é um gráfico com barras retangulares e co

Felipe Leite 0 Nov 5, 2021
SwiftUICharts - A simple line and bar charting library that supports accessibility written using SwiftUI.

SwiftUICharts - A simple line and bar charting library that supports accessibility written using SwiftUI.

Majid Jabrayilov 1.4k Jan 9, 2023
🎈 Curated collection of advanced animations that I have developed using (Swift UI for iOS) and (React Native for iOS/Android). Source code is intended to be reused by myself for future projects.

?? Curated collection of advanced animations that I have developed using (Swift UI for iOS) and (React Native for iOS/Android). Source code is intended to be reused by myself for future projects.

Artem Moshnin 5 Apr 3, 2022
Demonstrate a way to build your own line chart without using any third-party library

LineChart This code demonstrate a way to build your own line chart without using any third-party library. It contains a simple yet effective algorithm

Van Hung Nguyen 0 Oct 17, 2021
Simple iOS Application built using UIKit displaying the list of Cryptocurrencies and a detailed screen with a line graph.

CryptoViewer Simple iOS Application built using UIKit displaying the list of Cryptocurrencies and a detailed screen with a line graph. Home Screen: Di

null 0 Jun 14, 2022
Using Swift Charts and Voiceover Chart Descriptor to compose music. 🤯

Chart de lune ?? Using Swift Charts and Voiceover Chart Descriptor to compose music. ?? Image source: https://hadikarimi.com/portfolio/claude-debussy-

An Trinh 31 Nov 21, 2022
Mac app for virtualizing Linux and macOS (supports M1/Apple Silicon)

Microverse is a thin virtualization app for macOS, which allows running Linux (and, soon, macOS) guest virtual machines, achieved with macOS' own virtualization framework.

Justin Spahr-Summers 121 Dec 21, 2022
Line plot like in Robinhood app in SwiftUI

RHLinePlot Line plot like in Robinhood app, in SwiftUI Looking for how to do the moving price label effect? Another repo here. P.S. Of course this is

Wirawit Rueopas 234 Dec 27, 2022
A simple and animated Pie Chart for your iOS app.

XYPieChart XYPieChart is an simple and easy-to-use pie chart for iOS app. It started from a Potion Project which needs an animated pie graph without i

XY Feng 1.7k Sep 6, 2022