Pull to refresh

Руководство по анимационному отображению представлений в таблице на Swift

Website development *Development for iOS *Swift *
Translation
Tutorial
Original author: Ray Fix
Стандартный UITableView – мощный и в тоже время гибкий способ для представления данных в Ваших приложениях; есть вероятность, что большинство приложений, которые Вы создаёте, будут использовать табличное представление в той или иной форме. Тем не менее, есть недостаток в том, что без некоторого уровня настройки, приложения будут выглядеть бледно и сливаться с тысячами подобных. Во избежание “скучных” таблиц, Вы можете добавить несколько подходящих анимационных изображений, которые «оживлять» приложение. Возможно, Вы видели подобное в приложении Google+, где ячейки в таблице буквально летают по экрану вместе с классной анимацией. Если не обращали на это внимания, Вы можете скачать здесь (бесплатно)! Также может быть полезным и интересным ознакомление с руководством по дизайну (design guidelines), которое Google выпустило на конференции 2014 I/O. Оно содержит много советов и примеров, как эффективно и правильно использовать анимацию в своих приложениях.


В этой статье, будет использоватся язык программировани Swift по улучшению, для существующего приложения, при прокрутке ячеек таблицы и перемещении изображения по вертикали. Также описываются способы преобразования в UIKit, и их удобное использование для того, чтобы избежать перегрузки слишком большим количеством действий, которые происходят одновременно на экране. Вы получите советы, как организовать программный код, чтобы задачи были простыми и понятными, а Ваш главный контроллер простым.

Для начала, Вам следует ознакомиться как работать с UITableView и с базовыми элементами в Swift. Если Вам нужно ознакомиться с этим, то Вы можете начать ознакомление с серий Swift Tutorial, которая научит Вас основам работы в языком Swift, касательно приложений по табличному представлению.

Начнем.

Скачайте стартовый проект и откройте его в Xcode 6. Вы увидете простое описание проекта (UITableViewController) подкласс (MainViewController) и настройку UITableViewCell (CardTableViewCell) для отображения разработчиков. Вы также найдёте пример класса Member, который описывает всю информацию о члене команды и знает, как извлечь эту информацию из JSON файла, который находится в внутри нашего приложения.

Скомпилируйте и запустите проект. Вы увидите следующее:

image

Превосходный дизайн, готовый к приданию ему особого колорита и усовершенствования

Приложение готово к использованию, но могло бы содержать немного больше индивидуализма, так сказать иметь свою “изюминку”. Это уже Ваша работа; используйте некоторые трюки с Core Animation, чтобы «оживить» ячейку с данными.

Определите самый простой возможный способ анимации

Для получения основной структуры приложения, начинайте с создания простого класса помощника. Перейдите File\New\File… и выберите тип iOS\Source\Swift File для пустого файла Swift. Кликните Next, назовите файл TipInCellAnimator.swift и затем кликните Create.

Замените содержимое файла следующим кодом:

import UIKit
 
class TipInCellAnimator {
  // placeholder for things to come -- only fades in for now
  class func animate(cell:UITableViewCell) {
    if let view = cell.contentView {
      view.layer.opacity = 0.1
      UIView.animateWithDuration(1.4) {
        view.layer.opacity = 1
      }
    }
  }
}


Этот простой класс содержит алгоритм, который берёт ячейку с данными, получает доступ к её содержанию (contentView) и устанавливает первоначальную прозрачность слоя в 0,1. Затем, через 1,4 секунды, программный код в закрывающемся выражении преобразует прозрачность слоя назад к 1.0.

Заметьте: выражение в Swift — это просто блок кода, который также может охватывать внешние переменные. Например, { } – простое выражение. Функции, обозначенные как func — примеры именных выражений. В Swift можно открывать функции внутри других функций.

Если Вы передали выражение в качестве последнего аргумента функции, Вы можете использовать специальный синтаксис trailing closure (конечное выражение) и перемещать выражение вне вызова функции.

Прочитайте больше о выражениях в Swift Programming Language book или прочтите статью об истории создания выражений (rich history of closures) в Wikipedia.


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

Запуск анимации

Для запуска анимации откройте файл MainViewController.swift и добавьте следующий метод:

override func tableView(tableView: UITableView!, willDisplayCell cell: UITableViewCell!,
    forRowAtIndexPath indexPath: NSIndexPath!) {
  TipInCellAnimator.animate(cell)
}


Этот алгоритм обозначен в UITableViewDelegate protocol и вызывается перед тем, как ячейка появляется на экране. Затем вызывается алгоритм класса TipInCellAnimator для каждой ячейке для того, чтобы запустить анимацию.

Скомпилируйте и запустите приложение. Прокрутите таблицу с информацией и смотрите как ячейка медленно исчезает:

image

Эффект вращения

Давайте сделаем наше приложение ещё более привлекательным, добавим вращение. Это работает так же, как и всплывающая анимация, однако Вы указываете как начало, так и конец преобразований.

Откройте файл TipInCellAnimator.swift и замените содержание следующим:

import UIKit
import QuartzCore // 1
 
class TipInCellAnimator {
  class func animate(cell:UITableViewCell) {
    if let view = cell.contentView {
      let rotationDegrees: CGFloat = -15.0
      let rotationRadians: CGFloat = rotationDegrees * (CGFloat(M_PI)/180.0)
      let offset = CGPointMake(-20, -20)
      var startTransform = CATransform3DIdentity // 2
      startTransform = CATransform3DRotate(CATransform3DIdentity,
        rotationRadians, 0.0, 0.0, 1.0) // 3
      startTransform = CATransform3DTranslate(startTransform, offset.x, offset.y, 0.0) // 4
 
      // 5
      view.layer.transform = startTransform
      view.layer.opacity = 0.8
 
      // 6
      UIView.animateWithDuration(0.4) {
        view.layer.transform = CATransform3DIdentity
        view.layer.opacity = 1
      }
    }
  }
}


На этот раз движение будет быстрее (0,4 секунды), всплывание более удобное и Вы получаете интересный эффект вращения. Ключ к вышеупомянутой анимации определяет матрица startTransform, которая и приводит ячейку назад в первоначальное положение. Разберёмся как это происходит:

1. Этот класс требует, чтобы QuartzCore был импортирован, т. к. он использует ключевые анимационные преобразования.
2. Начинайте с распознавания преобразования, которое является арифметическим выражением для «фиктивной операции». Это преобразование изображения по умолчанию.
3. Перейдите к CATransform3DRotate, чтобы получить вращение на 15 градусов, где знак отрицания указывает на вращение против часовой стрелки. Движение осуществляется вокруг осей 0.0, 0.0, 1.0 и представляет собой вертикальную ось z, где x=0, y=0 и z=1.
4. Применение одной лишь ротации является недостаточным, так как происходит вращение таблицы/графика относительно его центра. Для того, чтобы сделать эффект переворота с угла, добавьте сдвиг или смещение, где отрицательные значения указывают на перемещение вверх и влево.
5. Установите результат преобразования как первоначальный вид.
6. Приведите в движение изображение и верните исходные значения.

Обратите внимание, чтобы Вы смогли создать окончательное преобразование, как показано на рисунке ниже:
image

Примечание: произвольная цепочка преобразований в конечном итоге может быть представлена одной матрицей. Если Вы изучали матричную алгебру в школе, то вспомните действие умножения матриц (multiplication of matrices). Каждый шаг умножает новое изменение, пока Вы не дойдёте до конечной матрицы.

Вы также заметите, что изменяется, так сказать, «детский» вид ячейки, а не сама ячейка. Вращение всей ячейки приведёт к тому, что часть сверху и снизу будет недоступна для обозрения, и мы получим странные визуальные эффекты, такие как, колебания и обрезание ячейки. ContentView ячейки содержит все составные части.

Не все свойства поддерживают анимацию. Руководство по программированию Core Animation (Core Animation Programming Guide) предоставляет список (list of animatable properties) для уточнений.

Скомпилируйте и запустите приложения. Смотрите, как ячейки с данными наклоняются:
image

Рефакторинг в Swift

Подлинная версия Objective-C обеспечивает единоразовое определение начала преобразования. В вышеупомянутой версии исходного кода он каждый раз вычисляется animate() по новому. Как это сделать в Swift?

Один из способов заключается в использовании неизменного хранилища, которое определяется переходом к выражению. Замените содержание файла TipInCellAnimator.swift на:

import UIKit
import QuartzCore
 
let TipInCellAnimatorStartTransform:CATransform3D = {
  let rotationDegrees: CGFloat = -15.0
  let rotationRadians: CGFloat = rotationDegrees * (CGFloat(M_PI)/180.0)
  let offset = CGPointMake(-20, -20)
  var startTransform = CATransform3DIdentity
  startTransform = CATransform3DRotate(CATransform3DIdentity,
    rotationRadians, 0.0, 0.0, 1.0)
  startTransform = CATransform3DTranslate(startTransform, offset.x, offset.y, 0.0)
 
  return startTransform
}()
 
class TipInCellAnimator {
  class func animate(cell:UITableViewCell) {
    if let view = cell.contentView {
 
      view.layer.transform = TipInCellAnimatorStartTransform
      view.layer.opacity = 0.8
 
      UIView.animateWithDuration(0.4) {
        view.layer.transform = CATransform3DIdentity
        view.layer.opacity = 1
      }
    }
  }
}


Обратите внимание на программный код, который генерирует startTransform; теперь он как свойство класса TipIn CellAnimatorStartTransform. Вместо определения свойства метода создания и изменений при каждом запросе, установите свойство преобразования по умолчанию, путём присвоения ему выражения и назначения пары пустых скобок. Скобки позволяют сразу же вызывать выражение и присваивать возвращаемое значение свойству. Эта идиома инициализации обговаривается в книге Apple’s Swift в разделе инициализация (initialization). Для более детальной информации смотрите «Установка свойства значения выражения или функции по умолчанию».

Примечание: было бы неплохо сделать в классе TipInCellAnimatorStartTransform свойство TipInCellAnimator, но на момент написания статьи, свойства класса, еще не реализованы в Swift.

Добавление ограничений к преобразованиям

Хотя эффект анимации довольно-таки лаконичный, используйте его осмотрительно. Если Вы когда-либо испытывали дискомфорт при просмотре презентации из-за злоупотребления звуковыми эффектами или эффектов анимации, тогда Вы имеете представление о том, что такое перенасыщение или злоупотребление. В своих проектах старайтесь, чтобы анимация присутствовала только при первом появлении ячейки – когда она прокручивается снизу вверх. При прокрутке обратно вверх, ячейки должны быть без анимации.

Необходимо разработать такой способ, чтобы избежать от повторной анимации показанных ранее ячеек. Для этого, Вы увидите Swift Dictionary (Словарь), который обеспечивает быстрый поиск по ключу.

Примечание: набор инструкций представляет собой неупорядоченную совокупность уникальных записей, не имеющих дубликатов, а массив — это упорядоченный набор, который допускает дубликаты. Библиотека Swift (The Swift Standard Library) не включает набор инструкций, но может лёгко воспроизводить Dictionary of Bools.

Штрафные санкции за использование Словаря (Dictionary), таким образом, малы, поэтому, возможно, команда разработчиков Swift убрала их из первого выпуска. Общим недостатком набора инструкций или ключей словаря является то, что они не гарантируют последовательности, однако, упорядочение Ваших ячеек произведено генератором данных, так что это не является проблемой.


Откройте MainViewController.swift и добавьте следующее свойство класса:

var didAnimateCell:[NSIndexPath: Bool] = [:]


Тут мы создаем пустой словарь (dictionary), который распознаёт NSIndexPath как ключ и Bools как свойства. Затем замените метод tableView(tableView:, willDisplayCell:, forRowAtIndexPath:) на следующий:

override func tableView(tableView: UITableView!, willDisplayCell cell: UITableViewCell!, 
                        forRowAtIndexPath indexPath: NSIndexPath!) {        
    if didAnimateCell[indexPath] == nil || didAnimateCell[indexPath]! == false {
        didAnimateCell[indexPath] = true
        TipInCellAnimator.animate(cell)
    }
}


Вместо того, чтобы анимировать каждый раз ячейку при её появлении при прокручивании вверх или вниз по таблице, убедитесь в том, что indexPath ячейки сохранен в словаре. Если это не так, значит ячейка была показана впервые, поэтому следует запустить анимацию и добавить indexPath к Вашему набору инструкций. Если он уже есть в наборе, Вам ничего не следует делать.

Скомпилируйте и запустите свой проект; проведите вверх и вниз по Tableview и Вы увидите только те ячейки, которые были анимированы при первом появлении на экране:

image

Что делать дальше?

В этом руководстве Вы добавили анимацию к стандартным способам управлением визуализацией. Детали реализации анимации не были прописаны в классе MainViewController; наоборот, они были вынесенны во вспомогательный класс. Поддержание обязанностей класса в активном состоянии, в частности для контроллеров отображения, является одной из основных проблем развития IOS. Вы можете загрузить готовый проект

Теперь, когда Вы изучили основы добавления анимации к ячейкам, попробуйте изменить значения Вашего преобразования, чтобы увидеть, какие ещё эффекты можно создать. Некоторые идеи:

1. Более быстрая или медленная анимация.
2. Больший угол наклона.
3. Разные смещения: если Вы измените угол поворота, то, скорее всего, нужно будет изменить смещение, чтобы картинка смотрела прямо. Как будет выглядеть изображение, если Вы полностью опустите смещение и будете использовать значение параметров (0, 0)?
4. Будьте креативными и создайте оригинальные образы.
5. Для продвинутых пользователей: можете ли вы получить эффект поворота таблицы по горизонтальной или вертикальной оси? Можете ли вы сделать так, чтобы создавалось впечатление полного переворота?
6. Для продвинутых пользователей: добавьте пункт else (другое) к tableView(tableView:, willDisplayCell:, forRowAtIndexPath:) и получите разные эффекты анимации, когда ячейки данных будут отображаться второй раз.
image
Сумасшедшие повороты, которые Вы можете применять к ячейкам данных.

Даже изучив простое руководство по созданию анимации из этой статьи, можно создавать бесконечное множество вариаций, опираясь на эту информацию. Анимация может быть отличным дополнением к действиям пользователя, например, переворачивание ячейки по кругу, постепенное затухание или появление при представлении или удаление ячейки.

p.s. Перевод не претендует на самый правильный и самый лучший перевод на хабре, если есть какие-то замечание, пишите в личку, буду править. Спасибо за понимание.
Tags:
Hubs:
Total votes 8: ↑6 and ↓2 +4
Views 11K
Comments 3
Comments Comments 3