- PVSM.RU - https://www.pvsm.ru -
После выхода на рынок iPhone 6s и iPhone 6s Plus с экранами, которые поддерживают технологию 3D Touch, а App Store практически сразу появилось приложение для взвешивая слив и персиков.

Не могу с уверенностью сказать почему именно этих фруктов, но могу сказать однозначно почему именно фруктов. Дело в том, что сенсор экрана iPhone работает по принципу определения утечки тока с поверхности сенсора, а для этой самой утечки нужен живой палец либо что-то, что обладает электрической емкостью. Думаю, каждый знает, что на пластиковые стилус или ноготь экраны i-девайсов не срабатывают. Именно поэтому взвесить на том приложении что-то металлическое не получалось. Но фрукты имеют электрическую емкость, на них срабатывает сенсор и нормально срабатывает непосредственно 3D Touch.
Очень быстро это приложение было удалено из App Store. Лично мне кажется, что это было сделано из-за недалеких американских пользователей, которые попытались взвесить на своих устройствах пудовые гири. Разумеется, устройства сломались и они их понесли в сервисные центры. А там они сказали что-то из серии: «Приложение скачано из официального магазина, и там не предупреждали, что нельзя…».
В итоге, подобных приложений нет в магазине, но никто нам не помешает создать его для себя.
Нам нужно написать приложение, которое состоит из одного контроллера, на котором будут приглашающая надпись, нарисованный круг в центре экрана, индикаторы веса в граммах и процентов от определяемой силы (дальше по тексту будет понятнее). При нажатии на экран в месте касания будет появляться круг, который будет увеличиваться или уменьшаться в зависимости от силы нажатия. Сразу нужно сказать, что на симуляторе подобное приложение протестировать не получится. Поэтому нужно будет запускать приложение на реальном устройстве. По окончанию должно получиться вот такое приложение:

Октройте XCode, выберите создание нового проекта, шаблон Single View Application

Перейдите в Storyboard, перетащите из библиотеки элементов на контроллер несколько UILabel, разместите их ближе к верхнему или нижнему краев контроллера. У меня получилось так:

Для эстетической привлекательности место куда будем класть предметы мы выделим красной окружностью. Можно взять уже готовую картинку с кругом, но это же не наш метод)). Круги мы нарисуем методами Core Graphics. Удобнее будет создать класс-наследник от UIView и уже с ним работать.
Добавьте в проект новый файл, назовите его ScaleView. Создайте в этом файле класс ScaleView который наследуется от UIView.

import UIKit
class ScaleView: UIView {
override func draw(_ rect: CGRect) {
}
}
Далее перейдите в StoryBoard, перенесите на контроллер из библиотеки элементов UIView и расположите его в центре нашего контроллера. Выберите только что добавленный UIView и в Identity Inspector задайте класс ScaleView, который мы создали ранее.

Также с помощью констрейнтов можно задать правила взаимного расположения элементов на экране. У меня это выглядит вот так:

Перейдите в файл ScaleView.swift. В классе ScaleView мы создали метод draw(_ rect:), который мы будем использовать для рисования внутри области отображения этого UIView.
Добавьте следующий код в метод draw(_ rect:)
override func draw(_ 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
}
Можно скомпилировать для проверки, однако также можно задать директиву для отображения изменений прямо в Interface Builder.
Вся магия в директиве @IBDesignable. Отметьте этой директивой класс ScaleView
import UIKit
@IBDesignable
class ScaleView: 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()
}
}
После этого перейдите в StoryBoard, немного подождите и вы увидите нарисованную красную окружность в центре ViewController

Давайте потренируемся и нарисуем еще один круг поменьше и потоньше. Для этого в файле ScaleView в метод draw(_ rect:) добавьте следующий код:
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()
Думаю, понятно и так что мы добавили. По сути мы добавили еще одну окружность, серого цвета, радиусов в четверть ширины ScaleView и шириной в одну точку.
Результаты в StoryBoard:

Финалом наших подготовительных работ будет создание аутлетов для ScaleView и двух UILabel, который буду показывать силу нажатия на экран в процентах и вес в граммах. Ctrl-перетасктвние элементов из ViewController создаст нужные аутлеты.
@IBOutlet weak var scaleView: ScaleView!
@IBOutlet weak var forceLabel: UILabel!
@IBOutlet weak var grammLabel: UILabel!
Итак, мы вплотную подошли к моменту измерения силы нажатия на экран. Перейдите во ViewController и в методе viewDidLoad() добавьте стартовые значения для всех UILabel
override func viewDidLoad() {
super.viewDidLoad()
forceLabel.text = "0% force"
grammLabel.text = "0 грамм"
}
Как и все процессы, связанные с нажатиями на экран, в контроллере их можно отловить в методе touchesMoved(_::). Данный метод срабатывает когда касания экрана происходят во времени. Т.е. Если палец стоит на экране или движется по нему срабатывает этот метод и можно отследить все касания и их свойства. Добавьте его во ViewController и напишите следующий код:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first { // 1
if #available(iOS 9.0, *) { // 2
if traitCollection.forceTouchCapability == UIForceTouchCapability.available { // 3
if touch.force >= touch.maximumPossibleForce { // 4
forceLabel.text = "100%+ force"
grammLabel.text = "385 грамм"
} else {
let force = (touch.force / touch.maximumPossibleForce) * 100 // 5
let grams = force * 385 / 100 // 6
let roundGrams = Int(grams) // 7
forceLabel.text = "(Int(force))% force" // 8
grammLabel.text = "(roundGrams) грамм"
}
}
}
}
}
Вся механика iOS приложения Весы заключается в этом методе. Все остальное, что мы будем делать дальше в этом уроке — это доработки. Всю основную работу мы уже сделали. Давайте разбирать по пунктам
Прежде чем запускать и проверять приложение нужно добавьте еще один метод, который срабатывает в момент, когда все касания на экран прекращаются touchesEnded(::), для того чтобы задать начальное положение наших UILabel и передать в них значения 0% и 0 грамм. Добавьте этот метод в класс ViewController.
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
forceLabel.text = "0% force"
grammLabel.text = "0 грамм"
}
Теперь можно компилировать приложение и проверять. Разумеется это нужно делать на реальном устройстве, чтобы увидеть результат. Симулятор не способен эмулировать силовые нажатия на экран.

Основной функционал готов, но я при написании этого приложение решил добавить три вещи:
Этими дополнениями мы займемся в следующей статье :-)
Автор: Артём Клименко
Источник [1]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/tutorial/286032
Ссылки в тексте:
[1] Источник: https://habr.com/post/417221/?utm_source=habrahabr&utm_medium=rss&utm_campaign=417221
Нажмите здесь для печати.