Задание 3. Решение — дополнительные пункты 4, 5 и 6. Окончание.

Screen Shot 2015-05-12 at 8.50.24 PM

Это решение Задания 3 — дополнительные пункты 4, 5 и 6. Обязательные пункты Задания, дополнительные пункты 1, 2 и 3, а также ссылки на текст самого Задания 3 можно посмотреть здесь:

Задание 3. Решение — обязательные пункты.
Задание 3. Решение — дополнительные пункты 1, 2 и 3.

Для окончательного решения код для Swift 1.2 находится на Github. Для Swift 2.0 код можно посмотреть на Github.

Пункт 4 дополнительный

При вращении прибора (или другом измении границ (bounds) ), разместите origin вашего графика по отношению к центру графического View, а не по отношению к верхнему левому углу.

Давайте рассмотрим класс GraphView нашего обобщенного пользовательского  View, которое строит графики. Определим еще одно public свойство в этом классе

Screen Shot 2015-05-14 at 5.55.45 PM
Это практически полная синтаксическая копия предыдущего свойства origin, но семантический смысл у него другой — это смещение начала координат графика по отношению к центру нашего пользовательского View. Свойство originRelativeToCenter хорошо тем, что его значение по умолчанию равно  CGPointZero и не зависит от геометрии View. Мы можем задать его даже на этапе, когда «геометрия»  нашего пользовательского View не определена.

Предыдущее public свойство  origin, означающее смещение начала координат графика по отношению к левому верхнему углу нашего пользовательского View, остается, так как именно на него настроено рисование осей координат и самого графика. Но оно становится вычисляемым свойством на основе originRelativeToCenter

Screen Shot 2015-05-11 at 8.27.12 PM

Заметьте, что для вычисления  origin понадобится центр graphCenter нашего  View, то есть геометрия должна быть уже определена к моменту использования  origin. Действительно,  origin будет запрашиваться только в функции drawInRect, которая существенно упростилась и в которой уже все outlets установлены, и согласно подсказке №8 Задания 3, геометрия полностью определена. Следовательно, никаких проблем с использованием origin у нас не будет.

Screen Shot 2015-05-11 at 8.35.09 PM

Определенное заново вычисляемое свойство origin лучше сделать в классе GraphView  private. У меня этого нет в текущем коде, но в окончательном варианте оно установлено как private. Вы можете сделать это сейчас. Во внешнем «мире», например, в  классе  GraphViewController, будем оперировать с originRelativeToCenter. Значение именно этого свойство будем запоминать  в NSUserDefaults и восстанавливать из NSUserDefaults. Эти манипуляции мы производим в другом классе  GraphViewController, классе нашего Controller. Этим будет заниматься private вычисляемая переменная originRelative (немного другое название, чем в классе GraphView).

Screen Shot 2015-05-11 at 8.40.13 PM

Когда мы используем originRelative переменную в правой части выражения {get}, то вы «достаем» данные из NSUserDefaults, а когда в левой {set}— «записываем» данные в NSUserDefaults.
Нам нужно «достать» из NSUserDefaults координаты начала координат графика относительно центра сразу после загрузки outlet со storyboard. У нас один  outlet — это обобщенный (generic) график graphView: GraphView! и в Наблюдателе Свойства этого автоматически подгружаемого  со storyboard свойства, мы устанавливаем значение свойству originRelativeToCenter нашему графику, то есть используем  originRelative переменную в правой части выражения.

Screen Shot 2015-05-11 at 8.45.38 PM
Теперь посмотрим, где мы записываем начало координат графика относительно центра в NSUserDefaults. Его значение может измениться при использовании жестов panning и  double-tapping (обязательный 11 пункт Задания 3). Запоминать в NSUserDefaults значение начало координат графика будем в методе «жизненного цикла» ViewWillDisappear нашего Controller

Screen Shot 2015-05-14 at 8.35.33 PM
Здесь мы используем  originRelative переменную в левой части выражения, следовательно идет «запись» в  NSUserDefaults.
Код получился простой и понятный.Теперь, если начало координат графика находится близко к центру, то при автовращении прибора, мы также получим начало координат близко к центру.

Screen Shot 2015-05-11 at 8.52.29 PM

Это будет выполняться системой автоматически при соответствующем определении возможных положений прибора в установках проекта

Screen Shot 2015-05-14 at 9.01.39 PM

Код для Swift 1.2 находится на  Github. Полное решение для Swift 2.0 можно посмотреть на Github.

Пункт 5 дополнительный

Добавьте Popover к вашему новому MVC, который будет сообщать о минимальном и максимальном y-значениях (и еще какую-нибудь статистику, если хотите) в области графика, показываемого в данный момент. Это потребует от вас создание еще одного MVC и segue к нему, используя popover segue. Это также потребует некоторого нового public API в вашем generic графическом View для предоставления статистики об области, в которой нарисован график.

Создаем специальную структуру Statistics для работы со статистикой, в которую включим расчет количества точек num, минимальное значение min, максимальное значение max и среднее значение avg. Эта структура инициализируются c нулевыми свойствами и имеет mutating метод calculate (y:CGFloat), который рассчитывает статистические параметры по мере поступления значений y. Структура  Statistics позволяет представить себя ввиде строки с помощью протокола Printable и его свойства description.
Screen Shot 2015-05-12 at 11.19.58 AM

Добавляем в класс  GraphView public свойство, соответствующее экземпляру этой структуры

Screen Shot 2015-05-14 at 9.17.05 PM

 

 Методы этого экземпляра используем при построении графика в drawCurveInRect. Нам понадобится всего две строки.

Screen Shot 2015-05-14 at 9.14.43 PM
Теперь у нас есть данные, которые мы должны отобразить в Popover. Popover не является самостоятельным View Controller, а служит для представления произвольного View Controller в виде Popover. Таким View Controller может быть фрагмент Text View Controller со storyboard из демонстрационного примера «Psychologist Popover» в Лекции 7. Можно скопировать из демонстрационного примера вначале файл TextViewController.swift, а затем сам фрагмент storyboard Text View Controller. Добавляем на MVC нашего графика кнопку (Bar Button Item) «Statistics«, соединяем ее с только что скопированным фрагментом  Text View Controller с помощью segue типа popover presentation и даем ему имя «Show Statistics«.

Screen Shot 2015-05-12 at 11.30.46 AM
Для отображения статистических параметров создаем специализированный subclass нашего более общего GraphViewController, имеющий имя StatisticsGraphViewController. Этот новый класс подверждает протокол  делегата для Popover презентации с целью подавления адаптивного поведения Popover  на приборах с горизонтальным размером .Compact. Об этом можно посмотреть специальный пост.

Screen Shot 2015-05-12 at 11.39.02 AM
Нажатие кнопки «Statistics» вызывает появление Popover со статистическими данными о графике, находящемся на экране. Popover имеет вид «маленького окошка» на всех приборах, а также в портретном и ландшафтном режимах.

Screen Shot 2015-05-12 at 11.53.43 AM

Код для Swift 1.2 находится на GithubПолное решение для Swift 2.0 можно посмотреть на Github.

Пункт 6 дополнительный

Сделайте калькулятор, который реагирует на изменение size class путем совершенно различного расположения элементов на пользовательском интерфейсе в среде различных size class (например, кнопок в различной сетке или даже добавлением различного количества операций в одном или другом size class). Когда вы делаете это, то ничего не должно ломаться!

Интерфейс в size классе Any-Any изменен: добавлены математические операции, кнопка построения графиков включена в клавиатуру калькулятора.

Screen Shot 2015-05-12 at 8.29.19 PM
Количество столбцов по горизонтали — 5, а по вертикали — 7.

Интерфейс для size класса Any-Compact содержит  по горизонтали 6 столбцов, а по вертикали — 6 строк.

Screen Shot 2015-05-12 at 8.40.30 PM
Кроме того в этом режиме пришлось поменять фонт для операций, содержащих 4 буквы: asin, acos, atan, так как на iPone 6+ в ландшафтном режиме названия этих операций не умещались.

Запустим наше приложение на iPhone 6+ в портретном и ландшафтном режимах.

Screen Shot 2015-05-12 at 8.50.24 PM
Запустим наше приложение на iPhone 6 в портретном и ландшафтном режимах.
Screen Shot 2015-05-12 at 8.54.51 PM
Запустим наше приложение на iPad 2 в ландшафтном режимах.

Screen Shot 2015-05-12 at 8.57.50 PM
Задание 3 выполнено.

Код для Swift 1.2 находится на Github. Полное решение для Swift 2.0 можно посмотреть на Github.

Задание 3. Решение — дополнительные пункты 4, 5 и 6. Окончание.: 2 комментария

    • Такого рода вопросы относятся к коммерческой тайне, которую без особых оснований раскрывать не принято.

Обсуждение закрыто.