Весы для айфона

Весы для айфона

После выхода на рынок 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 }

  1. Получаем графический контекст, в котором мы буде рисовать
  2. Задаем цвет, которым будем рисовать. В данном случае. — это красный цвет
  3. Устанавливаем ширину линии, которой будем рисовать.
  4. Задаем путь для рисования в виде дуги, центр которой расположен в центре ScaleView, радиусом равным половине ширины ScaleView минус 14 ( это чтобы вписать дугу в видимую область View), и длинной дуги — по всей окружности в 360 градусов. Прошу учесть, что мои цифры ширины жестко заданы в предыдущем пункте с помощью констрейнтов.
  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 приложения Весы заключается в этом методе. Все остальное, что мы будем делать дальше в этом уроке — это доработки. Всю основную работу мы уже сделали. Давайте разбирать по пунктам

  1. Из всего множества касаний экрана выберем первое
  2. Данная директива проверяет установленную операционную систему на устройстве и пропускает далее только если версия операционной системы 9.0 и более. Работа с 3D Touch стала возможной только с 9-ой версии iOS. Пытаться его обработать в боль ранних версиях не имеет смысла
  3. А в этой строке идет проверка устройства на поддержку экрана с функцией 3D Touch. Ведь iOS версии 10 может стоять и на iPhone 6, но от этого экран этого смартфона не начнет различать силу нажатия. Данную проверку необходимо проводить по строгому требованию Apple
  4. У касания есть свойство force в которе передается сила нажатия каждый раз, как срабатывает метод touchesMoved(_::). И в этой строке мы сравниваем значение текущей силы нажатия и максимально возможного значения силы нажатия. И если сила нажатия больше максимальной, то в наши UILabel мы передаем максимальные значения, а именно — 100 % силы и 385 грамм. Тут следует отметить почему именно 385 грамм. Дело в том, что технология 3D Touch сделана именно так, что 100% силы нажатия соответствуют 385-ти граммам. Соответственно получай процент силы нажатия мы можем легко вычислить вес в граммах.
  5. Вот тут эти вычисления и делаем. В этой строке вычисляем процент силы нажатия
  6. Тут вычислим вес в граммах, исходя из формулы 100% = 385 грамм
  7. Это простое округление граммов до целого
  8. Передаем значения процента силы и веса в граммах в наши UILabel

Прежде чем запускать и проверять приложение нужно добавьте еще один метод, который срабатывает в момент, когда все касания на экран прекращаются touchesEnded(::), для того чтобы задать начальное положение наших UILabel и передать в них значения 0% и 0 грамм. Добавьте этот метод в класс ViewController.
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { forceLabel.text = «0% force» grammLabel.text = «0 грамм» }
Теперь можно компилировать приложение и проверять. Разумеется это нужно делать на реальном устройстве, чтобы увидеть результат. Симулятор не способен эмулировать силовые нажатия на экран.

Основной функционал готов, но я при написании этого приложение решил добавить три вещи:

  1. При достижении максимального значения я хочу чтобы срабатывал виброотклик
  2. Обновление значений в UILabel происходят очень быстро, (я думаю вы это заметили при тестировании) поэтому нужно добавить некую плавность.
  3. В месте нажатия должен появляться полупрозрачный круг. Его диаметр должен увеличиваться по мере увеличения силы нажатия и уменьшаться по мере уменьшения силы нажатия

Этими дополнениями мы займемся в следующей статье 🙂

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

Не могу с уверенностью сказать почему именно этих фруктов, но могу сказать однозначно почему именно фруктов. Дело в том, что сенсор экрана iPhone работает по принципу определения утечки тока с поверхности сенсора, а для этой самой утечки нужен живой палец либо что-то, что обладает электрической емкостью. Думаю, каждый знает, что на пластиковые стилус или ноготь экраны i-девайсов не срабатывают. Именно поэтому взвесить на том приложении что-то металлическое не получалось. Но фрукты имеют электрическую емкость, на них срабатывает сенсор и нормально срабатывает непосредственно 3D Touch.

Очень быстро это приложение было удалено из App Store. Лично мне кажется, что это было сделано из-за недалеких американских пользователей, которые попытались взвесить на своих устройствах пудовые гири. Разумеется, устройства сломались и они их понесли в сервисные центры. А там они сказали что-то из серии: «Приложение скачано из официального магазина, и там не предупреждали, что нельзя…».

В итоге, подобных приложений нет в магазине, но никто нам не помешает создать его для себя.

Задача

Нам нужно написать приложение, которое состоит из одного контроллера, на котором будут приглашающая надпись, нарисованный круг в центре экрана, индикаторы веса в граммах и процентов от определяемой силы (дальше по тексту будет понятнее). При нажатии на экран в месте касания будет появляться круг, который будет увеличиваться или уменьшаться в зависимости от силы нажатия. Сразу нужно сказать, что на симуляторе подобное приложение протестировать не получится. Поэтому нужно будет запускать приложение на реальном устройстве. Как это сделать можно прочитать в статье Запуск и тестирование своих iOS-приложений на устройстве без аккаунта разработчика и без Jailbreak. По окончанию должно получиться вот такое приложение:

Создание проекта

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

Построение интерфейса в Xcode

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

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

Добавьте в проект новый файл, назовите его ScaleView. Создайте в этом файле класс ScaleView который наследуется от UIView.

// // proSwift.ru // import UIKit class ScaleView: UIView { override func draw(_ rect: CGRect) { } }

Далее перейдите в StoryBoard, перенесите на контроллер из библиотеки элементов UIView и расположите его в центре нашего контроллера. Выберите только что добавленный UIView и в Identity Inspector задайте класс ScaleView, который мы создали ранее.

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

Рисуем круги

Перейдите в файл ScaleView.swift. В классе ScaleView мы создали метод draw(_ rect:), который мы будем использовать для рисования внутри области отображения этого UIView.

Добавьте следующий код в метод draw(_ rect:)

// // proSwift.ru // 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 }

  1. Получаем графический контекст, в котором мы буде рисовать
  2. Задаем цвет, которым будем рисовать. В данном случае. — это красный цвет
  3. Устанавливаем ширину лини, которой будем рисовать.
  4. Задаем путь для рисования в виде дуги, центр которой расположен в центре ScaleView, радиусом равным половине ширины ScaleView минус 14 ( это чтобы вписать дугу в видимую область View), и длинной дуги — по всей окружности в 360 градусов. Прошу учесть, что мои цифры ширины жестко заданы в предыдущем пункте с помощью констрейнтов.
  5. Рисуем по заданному пути заданными параметрами

Можно скомпилировать для проверки, однако также можно задать директиву для отображения изменений прямо в Interface Builder. Также как мы делали в циклах статей CALayer, или как закруглить углы, сделать тень и градиент на Swift

Вся магия в директиве @IBDesignable. Отметьте этой директивой класс ScaleView

// // proSwift.ru // 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:) добавьте следующий код:

// // proSwift.ru // 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() // ЭТО ДОБАВИТЬ 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 создаст нужные аутлеты.

// // proSwift.ru // @IBOutlet weak var scaleView: ScaleView! @IBOutlet weak var forceLabel: UILabel! @IBOutlet weak var grammLabel: UILabel!

Непосредственно — весы

Итак, мы вплотную подошли к моменту измерения силы нажатия на экран. Перейдите во ViewController и в методе viewDidLoad() добавьте стартовые значения для всех UILabel

// // proSwift.ru // override func viewDidLoad() { super.viewDidLoad() forceLabel.text = «0% force» grammLabel.text = «0 грамм» }

Как и все процессы, связанные с нажатиями на экран, в контроллере их можно отловить в методе touchesMoved(_::). Данный метод срабатывает когда касания экрана происходят во времени. Т.е. Если палец стоит на экране или движется по нему срабатывает этот метод и можно отследить все касания и их свойства. Добавьте его во ViewController и напишите следующий код:

// // proSwift.ru // 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 приложения Весы заключается в этом методе. Все остальное, что мы будем делать дальше в этом уроке — это доработки. Всю основную работу мы уже сделали. Давайте разбирать по пунктам

  1. Из всего множества касаний экрана выберем первое
  2. Данная директива проверяет установленную операционную систему на устройстве и пропускает далее только если версия операционной системы 9.0 и более. Работа с 3D Touch стала возможной только с 9-ой версии iOS. Пытаться его обработать в боль ранних версиях не имеет смысла
  3. А в этой строке идет проверка устройства на поддержку экрана с функцией 3D Touch. Ведь iOS версии 10 может стоять и на iPhone 6, но от этого экран этого смартфона не начнет различать силу нажатия. Данную проверку необходимо проводить по строгому требованию Apple
  4. У касания есть свойство force в которе передается сила нажатия каждый раз, как срабатывает метод touchesMoved(_::). И в этой строке мы сравниваем значение текущей силы нажатия и максимально возможного значения силы нажатия. И если сила нажатия больше максимальной, то в наши UILabel мы передаем максимальные значения, а именно — 100 % силы и 385 грамм. Тут следует отметить почему именно 385 грамм. Дело в том, что технология 3D Touch сделана именно так, что 100% силы нажатия соответствуют 385-ти граммам. Соответственно получай процент силы нажатия мы можем легко вычислить вес в граммах.
  5. Вот тут эти вычисления и делаем. В этой строке вычисляем процент силы нажатия
  6. Тут вычислим вес в граммах, исходя из формулы 100% = 385 грамм
  7. Это простое округление граммов до целого
  8. Передаем значения процента силы и веса в граммах в наши UILabel

Прежде чем запускать и проверять приложение нужно добавьте еще один метод, который срабатывает в момент, когда все касания на экран прекращаются touchesEnded(::), для того чтобы задать начальное положение наших UILabel и передать в них значения 0% и 0 грамм. Добавьте этот метод в класс ViewController.

// // proSwift.ru // override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { forceLabel.text = «0% force» grammLabel.text = «0 грамм» }

Теперь можно компилировать приложение и проверять. Разумеется это нужно делать на реальном устройстве, чтобы увидеть результат. Симулятор не способен эмулировать силовые нажатия на экран.

Доработки

Основной функционал готов, но я при написании этого приложение решил добавьте две вещи:

  1. При достижении максимального значения я хочу чтобы срабатывал виброотклик как в статье Haptic feedback на iPhone 6s
  2. Обновление значений в UILabel происходят очень быстро, (я думаю вы это заметили при тестировании) поэтому нужно добавить некую плавность.
  3. В месте нажатия должен появляться полупрозрачный круг. Его диаметр должен увеличиваться по мере увеличения силы нажатия и уменьшаться по мере уменьшения силы нажатия

Два первых пункта я не смогу отобразить ни с помощью скриншотов ни с помощью анимированных gif. Поэтому сделайте дополнения, описанные ниже и проверяете самостоятельно на своих устройствах. А вот третий пункт я продемонстрирую. Но давайте дополнения сделаем все вместе.

Виброотклик Haptic feedback

Импортируем фрэеймворк AudioToolbox перед декларацией класса ViewController, а также добавим свойство isPalySound для исключения многократного проигрывания виброотклика.

// // proSwift.ru // import UIKit import AudioToolbox class ViewController: UIViewController { @IBOutlet weak var scaleView: ScaleView! @IBOutlet weak var forceLabel: UILabel! @IBOutlet weak var grammLabel: UILabel! var isPlaySound = true …

Далее внесите изменения в метод touchesMoved(::), чтобы он выглядел следующим образом:

// // proSwift.ru // override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { if let touch = touches.first { cicrcleView.center = touch.location(in: view) if #available(iOS 9.0, *) { if traitCollection.forceTouchCapability == UIForceTouchCapability.available { if touch.force >= touch.maximumPossibleForce { forceLabel.text = «100%+ force» grammLabel.text = «385 грамм» if isPlaySound { // Добавления // 1 AudioServicesPlaySystemSound(1519) isPlaySound = false // 2 } } else { let force = (touch.force / touch.maximumPossibleForce) * 100 let grams = force * 385 / 100 let roundGrams = Int(grams) isPlaySound = true // Добавления // 3 forceLabel.text = «\(Int(force))% force» grammLabel.text = «\(roundGrams) грамм» } } } } }

Ничего сложного — при запуске iOS приложения, а в данном случае при инициализации ViewController и создании свойства класса isPlaySound мы включаем возможность проигрывания звуков — в том числе и виброоткликов. При достижении максимальной силы нажатия происходит проверка isPlaySound (1) и если он true то выполняется вибрация и сразу срабатывает запрет (2) на проигрывание вибрации. Этот запрет снимается (3), если сила нажатия становится меньше максимально возможного значения.

Плавность обновления

Теперь про плавность. Обновления надписей присходит очень быстро, со скоростью срабатывания метода touchesMoved(::), а это несколько сотен срабатываний в секунду. Для Уменьшения частоты обновления надписи я добавил свойство класса ViewController isUpdate и поставил наблюдателей свойств didSet.

// // proSwift.ru // var isUpdate = true { didSet { if isUpdate == false { DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { self.isUpdate = oldValue } } } }

Суть подобной конструкции в том, что как только мы устанавливаем данное свойство в значение false оно возвращается в значение true через 0,01 секунды. Соответственно при записи текста в UILabel мы будем устанавливать значение свойства isUpdate в значение false и не позволим обновлять надписи пока оно не станет true. Поэтому обновления записей будет происходить у нас не чаще одного раза в сотую доли секунды.

В методе touchesMoved(::) в ветке, где мы выводим показания % силы и веса в граммах измените код следующим образом:

// // proSwift.ru // if isUpdate { forceLabel.text = «\(Int(force))% force» grammLabel.text = «\(roundGrams) грамм» isUpdate = false }

Этого будет достаточно для придания плавности при обновлении надписей

Визуализация касания

Сначала давайте создадим UIView и сделаем его полупрозрачным и круглой формы. Для этого добавим свойство класса ViewController и сделаем первоначальные настройки в методе viewDidLoad()

// // proSwift.ru // let cicrcleView = UIView(frame: CGRect(x: 0, y: 0, width: 80, height: 80)) // View 80 на 80 override func viewDidLoad() { super.viewDidLoad() forceLabel.text = «0% force» grammLabel.text = «0 грамм» cicrcleView.layer.cornerRadius = 40 // Закруглили углы по половине ширины View — получлся круг cicrcleView.alpha = 0.6 // Прозрачность 60% cicrcleView.backgroundColor = UIColor.red }

Свойство есть, в нем есть View, но вот в какой момент его добавить на экран? Логично, что в момент начала касания. Во ViewController нужно добавить метод touchesBegan(::)

// // proSwift.ru // override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { if let touch = touches.first { cicrcleView.center = touch.location(in: view) // 1 view.addSubview(cicrcleView) // 2 } }

Также выбираем из множества касаний первое и работе с этим касанием

  1. Устанавливаем координаты центра circleView в точку касания
  2. Добавляем cicrcleView на экран

В метод touchesMoved(::) в ветке, где обрабатываются проценты и вес в граммах нужно добавьте строку:

// // proSwift.ru // cicrcleView.transform = CGAffineTransform.init(scaleX: CGFloat(1 + (grams / 5) / 20), y: CGFloat(1 + (grams / 5) / 20))

Тут мы задаем матрицу трансформации для увеличения размеров cicrcleView по высоте и ширине. Значения которые я передал в эту матрицу — это результат подбора наиболее удобных значений. Подбором методом «тыка». Так что можете поэкспериментировать и выбрать значения, которые удобны вам.

Ну и наконец при завершении касаний нужно отменить трансформацию для cicrleView и убрать его с экрана. У нас уже есть метод, где можно это отработать. В метод touchesEnded(::) добавьте две строки:

// // proSwift.ru // override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { forceLabel.text = «0% force» grammLabel.text = «0 грамм» // Добавить cicrcleView.removeFromSuperview() // Убрали круг cicrcleView.transform = .identity // Убрали трансформацию для круга }

Полностью код ViewController выглядит так:

// // proSwift.ru // import UIKit import AudioToolbox class ViewController: UIViewController { @IBOutlet weak var scaleView: ScaleView! @IBOutlet weak var forceLabel: UILabel! @IBOutlet weak var grammLabel: UILabel! var isPlaySound = true var isUpdate = true { didSet { if isUpdate == false { DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { self.isUpdate = oldValue } } } } let cicrcleView = UIView(frame: CGRect(x: 0, y: 0, width: 80, height: 80)) override func viewDidLoad() { super.viewDidLoad() forceLabel.text = «0% force» grammLabel.text = «0 грамм» cicrcleView.layer.cornerRadius = 40 cicrcleView.alpha = 0.6 cicrcleView.backgroundColor = UIColor.red } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { if let touch = touches.first { cicrcleView.center = touch.location(in: view) // 1 view.addSubview(cicrcleView) // 2 } } override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { if let touch = touches.first { cicrcleView.center = touch.location(in: view) if #available(iOS 9.0, *) { if traitCollection.forceTouchCapability == UIForceTouchCapability.available { if touch.force >= touch.maximumPossibleForce { forceLabel.text = «100%+ force» grammLabel.text = «385 грамм» if isPlaySound { AudioServicesPlaySystemSound(1519) isPlaySound = false } } else { let force = (touch.force / touch.maximumPossibleForce) * 100 let grams = force * 385 / 100 let roundGrams = Int(grams) isPlaySound = true if isUpdate { forceLabel.text = «\(Int(force))% force» grammLabel.text = «\(roundGrams) грамм» isUpdate = false } cicrcleView.transform = CGAffineTransform.init(scaleX: CGFloat(1 + (grams / 5) / 20), y: CGFloat(1 + (grams / 5) / 20)) } } } } } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { forceLabel.text = «0% force» grammLabel.text = «0 грамм» cicrcleView.removeFromSuperview() cicrcleView.transform = .identity } }

Код файла ScaleView:

// // proSwift.ru // 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() 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() } }

Ссылка проекта на GitHub

Многим из нас со школьной скамьи известно, что нормальный вес человека рассчитывается по нехитрой формуле «масса = рост – 100». Впрочем, здравомыслящий человек может возразить, что 80 кг у спортсмена и 80 кг у обладателя пивного живота — это, как говорят в Одессе, две большие разницы. Произвести правильные замеры могут смарт-весы Xiaomi Mi Scale 2.

Полное название гаджета — Xiaomi Mi Body Composition Scale, его широкий функционал только начинается с измерения массы тела, а приставка «смарт» не означает наличие беспроводных динамиков, RGB-подсветки и прочей бесполезной электроники, здесь все по делу.

Дизайн Xiaomi Mi Body Composition Scale, упаковка и подготовка к использованию

Собственно, для работы Xiaomi Mi Scale 2 нужны лишь четыре батарейки типа ААА (в первой версии смарт-весов использовался тип АА), которые могут присутствовать в комплекте поставки. Впрочем, в большинстве случаев элементы питания в коробку не кладут, дабы избежать проблем при транспортировке по воздуху, тогда приобрести их нужно будет самостоятельно, благо хватает одного комплекта более чем на год использования.

Разработчики прислушались к фидбекам владельцев весов первого поколения и сделали Xiaomi Mi Scale 2 гораздо более легкими за счет изменения фронтальной стеклянной панели. В качестве материала на лицевой панели используется прочный ABS-пластик, имеющий антискользящее покрытие для обеспечения безопасности, даже если вы встанете на весы с мокрыми ногами.

Прорезиненные «ножки» снизу теперь имеют более жесткую конструкцию. LED-дисплей, отображающий индикаторы загрузки и массу, снова спрятали — он появляется лишь при активном использовании устройства.

Весы выглядят очень современно и станут идеальным дополнением к интерьеру любого дома.

Как работает Xiaomi Mi Scale 2

Большинство измерений, которые делает Xiaomi Mi Scale 2, производится посредством пропускания электрического заряда через тело пользователя, поэтому на весы, желательно установленные на твердую ровную поверхность, нужно вставать босыми сухими ногами, дотрагиваясь до всех четырех стальных пластин-электродов (в противном случае будет получен лишь вес пользователя). По этой причине, к слову, использовать Xiaomi Mi Scale 2 не рекомендуется людям с установленными кардиостимуляторами.

На встроенном дисплее смарт-весов отображается лишь масса в килограммах, в то время как полный анализ тела отправляется по Bluetooth 4.0 в смартфон или планшет пользователя, где интегрируется с другими данными фирменного приложения Mi Fit (), которое, в свою очередь, делится данными со штатным приложение iOS Здоровье.

За считанные секунды устройство выдает следующие показатели:

  • Масса тела;
  • Индекс массы тела (именно с этой цифрой работают все диетологи, фитнес-тренеры и т.д.);
  • Объем мышц;
  • Уровень метаболизма;
  • Коэффициент жира;
  • Уровень висцерального жира (который образуется вокруг внутренних органов);
  • Костная масса;
  • Количество воды в организме;
  • Тип телосложения;
  • Общее состояние организма.

Получив конкретные показатели по каждому из пунктов, пользователь также видит отклонения от нормы в ту или другую сторону и, соответственно, может самостоятельно корректировать образ жизни — наращивать объем мышц тренировками, пить больше воды для поднятия уровня жидкости и т.д.

Xiaomi Mi Body Composition Scale – весы для всей семьи

Весы Xiaomi Mi Scale 2 способны идентифицировать детей и взрослых по отдельности. Кроме того, устройство автоматически определяет каждого члена семьи и могут хранить до 16 пользовательских профилей (необходимо создание отдельного аккаунта).

Характеристики весов Xiaomi Mi Body Composition Scale

  • Размеры: 300 × 300 × 20 мм;
  • Вес: 1,6 кг;
  • Диапазон взвешивания: 5 кг – 150 кг;
  • Единицы измерения: цзинь, килограммы, фунты (по выбору);
  • Погрешность измерения: 50 г;
  • Материал: АБС-пластик;
  • Совместимость: Bluetooth 4.0;
  • Рабочая температура: 0℃ – 40℃;
  • Аккумулятор: 4 аккумулятора формата ААА;
  • Весы совместимы с устройствами на Android 4.4 и новее, а также iOS 8 и новее.

Как уже говорилось выше, данные от смарт-весов Xiaomi Mi Scale 2 могут комбинироваться в приложениях с показателями от других смарт-гаджетов, например:

  • фитнес-браслета Xiaomi Mi Band 3;
  • умных кроссовок для бега и тренировок Xiaomi Mija Smart Shoes;
  • электрической зубной щетки Xiaomi Soocare X3;
    и т.д.

Купить весы Xiaomi Mi Scale 2

4 марта 2019 Метки: iFaq, Аксессуары, Гаджеты с AliExpress, Здоровье, Новости Apple.

Ваш вес колеблется ежедневно. В отличие от других приложений, Scelta сравнивает средние показатели и показывает ваш фактический прогресс!
Если вы регулярно взвешиваете себя, вы знаете проблему: вес тела колеблется изо дня в день, и трудно сказать, действительно ли вы похудели, набрали вес или просто тяжелый день. Соленые продукты, гидратация, сон, стресс и гормональные колебания — вот лишь некоторые из факторов, которые могут сильно повлиять на вес в краткосрочной перспективе.
Чтобы понять ваш прогресс, средние значения за определенные промежутки времени всегда следует друг другом. Например, среднее значение за последние 14 дней с таким же средним значением пару недель назад.
Расчет этой «погрешности» сделает за вас Scelta! Scelta делает контроль веса доступным, значимым, приносящим массу удовольствия, при этом невероятно мотивируя.
Диета для потери веса, контроль веса в процессе набора мысса, или если вы просто хотите поддерживать ваш текущий вес: Scelta мотивирует вас на достижение ваших личных целей.
Scelta синхронизирует данные с Apple Health App: Scelta использует приложение «Здоровье» на вашем iPhone для просмотра существующих данных о весе и сохранения новых данных о нем. Поэтому Scelta попросит вас доступ к вашим данным. Данные веса видны только вам и не будут отправляться через Интернет. Достижения, открытые вами в Scelta, основаны на том, насколько хорошо вы выполняете поставленные цели, а не ваших фактических весовых показателей. Ваша собственная цель также видна только вам.


Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *