3DTouch - Scales on the iPhone: Getting Started

  • Tutorial
After the launch of the iPhone 6s and iPhone 6s Plus with screens that support 3D Touch technology , an application for weighing plums and peaches almost immediately appeared in the App Store.

image

I can’t say with certainty why it is these fruits, but I can definitely say why it is fruit. The fact is that the iPhone screen sensor works on the principle of determining the leakage of current from the sensor surface, and for this leakage you need a live finger or something that has an electrical capacity. I think everyone knows that the plastic stylus or nail screens i-devices do not work. That is why it was impossible to weigh something metallic on that application. But fruits have an electrical capacitance, the sensor works on them and 3D Touch directly works normally .

Very quickly, this application was removed from the App Store. Personally, it seems to me that this was done because of the narrow-minded users who tried to weigh the weights on their devices. Of course, the devices broke down and they carried them to the service centers. And there they said something from the series: "The application was downloaded from the official store, and they did not warn there that it was impossible ...".

As a result, these applications are not in the store, but no one will hurt us to create it for ourselves.

Task


We need to write an application that consists of a single controller, on which there will be an inviting inscription, a drawn circle in the center of the screen, weight indicators in grams and percent of the defined force (later in the text will be clearer). When you tap the screen, a circle will appear at the touch, which will increase or decrease depending on the pressing force. Just need to say that on the simulator such an application test fails. Therefore, you will need to run the application on a real device. At the end, you should get this application:

image

Creating a project


Oktroyte the XCode , choose to create a new project template Single View Application

image

Build interface in Xcode


Go to the Storyboard , drag a few UILabels from the library of elements onto the controller , place them closer to the top or bottom edges of the controller. I did it like this:

image

For aesthetic appeal, the place where we put the objects will be highlighted with a red circle. You can take a ready-made picture with a circle, but this is not our method)). We draw circles using Core Graphics techniques . It will be more convenient to create a descendant class from UIView and already work with it.

Add a new file to the project, name it ScaleView . Create a ScaleView class in this file that inherits from UIView .

image

import UIKit
classScaleView: UIView{
    overridefuncdraw(_ rect: CGRect) {
    }
}

Next, go to StoryBoard , transfer it to the controller from the UIView element library and position it in the center of our controller. Select the newly added UIView and in the Identity Inspector set the ScaleView class we created earlier.

image

Also with the help of constraints, you can set the rules for the relative position of elements on the screen. It looks like this to me:

image

Draw circles


Navigate to the ScaleView.swift file . In the ScaleView class , we created the draw (_ rect :) method , which we will use to draw inside the display area of ​​this UIView .

Add the following code to the draw method (_ rect :)

overridefuncdraw(_ rect: CGRect) {
    let context = UIGraphicsGetCurrentContext() // 1
    context?.setStrokeColor(UIColor.red.cgColor) // 2
    context?.setLineWidth(14.0) // 3
    context?.addArc(center: CGPoint(x: 375 / 2, y: 375 / 2), radius: 375 / 2 - 14, startAngle: 0, endAngle: 2 * CGFloat(M_PI), clockwise: true) // 4
    context?.strokePath() // 5
}

  1. We get the graphic context in which we will draw
  2. Set the color with which we will draw. In this case. - it is red color
  3. Set the width of the line with which we will draw.
  4. Set the drawing path in the form of an arc, the center of which is located in the center of ScaleView, with a radius equal to half the width of ScaleView minus 14 (this is to inscribe the arc in the visible View), and a long arc around the whole circle of 360 degrees. Please note that my width digits are strictly specified in the previous paragraph using constraints.
  5. We draw on the set way with the set parameters

You can compile for verification, but you can also specify a directive to display the changes directly in Interface Builder .

All the magic in the @IBDesignable directive . Mark ScaleView with this directive .

import UIKit
@IBDesignableclassScaleView: UIView {
override func draw(_rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()
        context?.setStrokeColor(UIColor.red.cgColor)
        context?.setLineWidth(14.0)
        context?.addArc(center: CGPoint(x: 375 / 2, y: 375 / 2), radius: 375 / 2 - 14, startAngle: 0, endAngle: 2 * CGFloat(M_PI), clockwise: true)
        context?.strokePath()
    }
}

After that, go to StoryBoard , wait a bit and you will see a red circle drawn in the center of the ViewController.

image

Let's work out and draw another smaller circle and thinner. To do this, in the ScaleView file , in the draw (_ rect :) method, add the following code:

context?.setLineWidth(1.0)
context?.setStrokeColor(UIColor.lightGray.cgColor)
context?.addArc(center: CGPoint(x: 375 / 2, y: 375 / 2), radius: 375 / 4 - 14, startAngle: 0, endAngle: 2 * CGFloat(M_PI), clockwise: true)
context?.strokePath()

I think it is clear and so we added. In fact, we added another circle, gray, a quarter-radius of ScaleView and one point wide.

Results in StoryBoard : The

image

final of our preparatory work will be the creation of outlets for ScaleView and two UILabel , which will show the force of clicking on the screen in percentage and weight in grams. Ctrl- dragging elements from the ViewController will create the necessary outlets.

@IBOutletweakvar scaleView: ScaleView!@IBOutletweakvar forceLabel: UILabel!@IBOutletweakvar grammLabel: UILabel!

Directly - Scales


So, we have come close to the moment of measuring the pressure on the screen. Go to ViewController and in the viewDidLoad () method add start values ​​for all UILabel

overridefuncviewDidLoad() {
    super.viewDidLoad()
    forceLabel.text = "0% force"
    grammLabel.text = "0 грамм"
}

Like all processes associated with clicking on the screen, in the controller they can be caught in the touchesMoved method (_: :) . This method works when the screen touches in time. Those. If the finger is on the screen or moving along it, this method works and you can track all the touches and their properties. Add it to ViewController and write the following code:

overridefunctouchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        iflet touch = touches.first { // 1if #available(iOS 9.0, *) { // 2if traitCollection.forceTouchCapability == UIForceTouchCapability.available { // 3if touch.force >= touch.maximumPossibleForce { // 4
                        forceLabel.text = "100%+ force"
                        grammLabel.text = "385 грамм"
                    } else {
                        let force = (touch.force / touch.maximumPossibleForce) * 100// 5let grams = force * 385 / 100// 6let roundGrams = Int(grams) // 7
                        forceLabel.text = "\(Int(force))% force"// 8
                        grammLabel.text = "\(roundGrams) грамм"
                  }
             }
         }
    }
}

All the mechanics of the iOS application Scales is in this method. Everything else that we will do next in this lesson is about improvements. We have already done all the basic work. Let's sort through the items

  1. Of all the many screen touches, choose the first one.
  2. This directive checks the installed operating system on the device and skips further only if the operating system version is 9.0 or more. Work with 3D Touch has become possible only with the 9th version of iOS. Trying to handle it in the pain of earlier versions does not make sense
  3. And in this line is checking the device to support the screen with the function of 3D Touch . After all, iOS version 10 can stand on the iPhone 6, but the screen of this smartphone will not begin to discern the force of pressing from this. This check is required by Apple’s strict request.
  4. A touch has a force property in which pressure is transmitted each time the touchesMoved (_: :) method works . And in this line we compare the value of the current pressing force and the maximum possible value of pressing force. And if the pressing force is greater than the maximum, then we transfer the maximum values to our UILabel , namely, 100 % of the force and 385 grams. Here it should be noted why it is 385 grams. The fact is that the 3D Touch technology is made in such a way that 100% of the pressing force correspond to 385 grams. Accordingly, get the percentage of pressing force, we can easily calculate the weight in grams.
  5. Here we make these calculations. In this line, we calculate the percentage of pressing force
  6. Here we calculate the weight in grams, based on the formula 100% = 385 grams
  7. This is a simple rounding of grams to the whole.
  8. We transfer the values ​​of the percentage of force and weight in grams to our UILabel

Before launching and testing the application, add another method that works when all touches on the screen stop touchesEnded (: :) , in order to set the initial position of our UILabel and transfer the values ​​of 0% and 0 grams to them. Add this method to the ViewController class .

overridefunctouchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        forceLabel.text = "0% force"
        grammLabel.text = "0 грамм"
}

Now you can compile the application and check. Of course, this should be done on a real device to see the result. The simulator is not able to emulate power clicking on the screen.

image

Improvements


The main functionality is ready, but when I wrote this application I decided to add three things:

  1. When the maximum value is reached, I want the vibration feedback to work.
  2. Updating the values ​​in UILabel is very fast (I think you noticed this when testing), so you need to add some smoothness.
  3. At the place of pressing should appear a translucent circle. Its diameter should increase as the pressing force increases and decrease as the pressing force decreases.

We will deal with these additions in the next article :-)

Only registered users can participate in the survey. Sign in , please.

Have you ever thought about such an application?


Also popular now: