Перевод статьи от автора Shubham Singh
Порадуйте своих пользователей привлекательной и увлекательной анимацией Таблицы
Табличные представления, несомненно, являются одним из наиболее часто используемых компонентов в любом приложении для iOS. Он используется для отображения одного столбца вертикально прокручиваемого содержимого, разделенного на строки.
Добавление анимации — отличный способ заинтересовать пользователя, и в то же время оно делает ваше приложение плавным и текучим.
Мы будем анимировать ячейки табличного представления с помощью метода UIView.animate класса UIView. Вот описание анимированного метода —
Анимируйте изменения в одном или нескольких представлениях, используя указанную продолжительность. Во время анимации взаимодействие с пользователем временно отключается для анимированных представлений.
Раньше мне не хотелось пробовать анимацию UIView, я извинялся перед собой, что это было слишком сложно, в этом не было необходимости, на обучение уйдет много времени. Только когда я прочитал несколько блестящих блогов, книги по UI / UX и осознал силу анимации, я убедил себя и просто начал пробовать анимацию.
Хорошо, мы добавим четыре типа анимации, вот как будет выглядеть анимация ячеек TableView:
. . .
Предпосылки
У вас должны быть некоторые знания о разработке приложений для iOS, даже если вы не слишком знакомы с концепциями, не стесняйтесь следовать за ними, я все объяснил просто. Все, что вам нужно, это MacBook, Xcode и некоторые знания AutoLayouts, метода UIView.animate и перечислений.
. . .
Вступление
Небольшое введение в представление, которое мы будем создавать в этом руководстве —
Представление будет иметь эти компоненты —
- Таблица
- Горизонтальный стэквью с 4 кнопками с одинаковым интервалом
С помощью этих 4 кнопок мы изменим анимацию ячеек TableViewHeader и TableView.
. . .
Руководство
Начните с создания одностраничного приложения в Xcode и выберите Storyboards в качестве пользовательского интерфейса.
Дизайн пользовательского интерфейса
Откройте Main.storyboard и выполните настройку представлений.
Вот список того, что мы добавили —
- Таблица — имеет ограничение сверху, справа, слева установленное в 0 и пропорции высоты 77% от представления.
- Горизонтальный Стэквью — имеет верхний, левый, правый ограничения установленные на 24.
- Кнопки — имеют ограничение по высоте 42, четыре из них уложены внутри stackView.
У каждой кнопки есть связанный с ней тег, добавьте их из атрибут инспектора.
- Button1 имеет тег, равный 1.
- Button2 имеет тег, равный 2.
- Button3 имеет тег, равный 3.
- Button4 имеет тег, равный 4.
Затем мы также создадим собственный TableViewClass со своим собственным XIB —
- Создайте новый класс CocoaTouch, установите подкласс как UITableViewCell и отметьте создание файла XIB.
- Откройте XIB файл класса UITableViewCell.
Для этой ячейки мы добавили один containerView внутри представления содержимого, для которого верхние и нижние ограничения установлены на 5, а левое и правое ограничения установлены на 12.
. . .
Напишем код
Первое, мы добавим кода в класс UITableViewCell
import UIKit class TableAnimationViewCell: UITableViewCell { override class func description() -> String { return "TableAnimationViewCell" } // MARK:- outlets for the viewController @IBOutlet weak var containerView: UIView! // properties for the tableViewCell var tableViewHeight: CGFloat = 62 var color = UIColor.white { didSet { self.containerView.backgroundColor = color } } override func awakeFromNib() { super.awakeFromNib() self.selectionStyle = .none self.containerView.layer.cornerRadius = 4 } }
Класс UITableViewCell очень простой
Мы добавили аутлет для containerView и установили две переменные —
- TableViewHeight — определяет высоту ячейки при доступе из viewController.
- Color — определяет цвет ячейки.
Мы также добавили код, чтобы установить для стиля выделения значение «Нет» и скруглить углы ячейки.
Затем, мы создали класс TableViewAnimator, который мы добавим в наш класс анимации таблицы.
Я рекомендую вам всегда создавать отдельный класс для анимации, чтобы он был универсальным и мог применяться к любым представлениям. Есть еще одно преимущество в создании настраиваемого класса: он остается легко настраиваемым, а желаемая продолжительность и эффект могут быть предоставлены в инициализаторе.
Давайте создадим класс TableViewAnimator
import UIKit // defining a typealias for ease of use typealias TableCellAnimation = (UITableViewCell, IndexPath, UITableView) -> Void // class to animate the tableViews with the presented animation final class TableViewAnimator { private let animation: TableCellAnimation init(animation: @escaping TableCellAnimation) { self.animation = animation } func animate(cell: UITableViewCell, at indexPath: IndexPath, in tableView: UITableView) { animation(cell, indexPath, tableView) } }
Здесь мы создали псевдоним типа и определили класс для TableViewAnimator.
Затем, давайте создадим перечисление TableAnimationFactory, и добавим 4 метода анимации —
///enums providing tableViewCell animations enum TableAnimationFactory { /// fades the cell by setting alpha as zero and then animates the cell's alpha based on indexPaths static func makeFadeAnimation(duration: TimeInterval, delayFactor: TimeInterval) -> TableCellAnimation { return { cell, indexPath, _ in cell.alpha = 0 UIView.animate( withDuration: duration, delay: delayFactor * Double(indexPath.row), animations: { cell.alpha = 1 }) } } /// fades the cell by setting alpha as zero and moves the cell downwards, then animates the cell's alpha and returns it to it's original position based on indexPaths static func makeMoveUpWithFadeAnimation(rowHeight: CGFloat, duration: TimeInterval, delayFactor: TimeInterval) -> TableCellAnimation { return { cell, indexPath, _ in cell.transform = CGAffineTransform(translationX: 0, y: rowHeight * 1.4) cell.alpha = 0 UIView.animate( withDuration: duration, delay: delayFactor * Double(indexPath.row), options: [.curveEaseInOut], animations: { cell.transform = CGAffineTransform(translationX: 0, y: 0) cell.alpha = 1 }) } } /// moves the cell downwards, then animates the cell's by returning them to their original position based on indexPaths static func makeMoveUpAnimation(rowHeight: CGFloat, duration: TimeInterval, delayFactor: TimeInterval) -> TableCellAnimation { return { cell, indexPath, _ in cell.transform = CGAffineTransform(translationX: 0, y: rowHeight * 1.4) UIView.animate( withDuration: duration, delay: delayFactor * Double(indexPath.row), options: [.curveEaseInOut], animations: { cell.transform = CGAffineTransform(translationX: 0, y: 0) }) } } /// moves the cell downwards, then animates the cell's by returning them to their original position with spring bounce based on indexPaths static func makeMoveUpBounceAnimation(rowHeight: CGFloat, duration: TimeInterval, delayFactor: Double) -> TableCellAnimation { return { cell, indexPath, tableView in cell.transform = CGAffineTransform(translationX: 0, y: rowHeight) UIView.animate( withDuration: duration, delay: delayFactor * Double(indexPath.row), usingSpringWithDamping: 0.6, initialSpringVelocity: 0.1, options: [.curveEaseInOut], animations: { cell.transform = CGAffineTransform(translationX: 0, y: 0) }) } } }
Мы добавили четыре типа анимации сюда, в перечисление, перечисление служит фабрикой анимации, которая предоставляет анимацию классу аниматора. Четыре анимации —
- Плавная анимация: Анимирует ячейки TableView на основе альфа ячейки.
- Анимация движения вверх: Анимирует ячейки TableView в зависимости от положения ячейки.
- Анимация движения-вверх-затухание: Анимирует ячейки TableView в зависимости от положения и альфа-канала ячейки.
- Анимация движения-вверх-отскока: Анимирует ячейки TableView в зависимости от положения ячейки с помощью пружинной анимации.
Далее, для простоты использования и во избежание загромождения ViewController, давайте создадим поставщика данных с помощью перечисления, которое обеспечивает анимацию из фабрики анимации, мы также добавим функцию для каждого случая перечисления, которая предоставляет заголовок для tableView.
Перечисления отлично подходят для сопоставления функций с случаями, они гарантируют, что код всегда без ошибок.
Давайте создадим файл Tables.swift и создадим перечисление TableAnimation для обеспечения данными ViewController —
import UIKit /// Enum provider for providing the animationTitle and an animation method from the factory enum TableAnimation { case fadeIn(duration: TimeInterval, delay: TimeInterval) case moveUp(rowHeight: CGFloat, duration: TimeInterval, delay: TimeInterval) case moveUpWithFade(rowHeight: CGFloat, duration: TimeInterval, delay: TimeInterval) case moveUpBounce(rowHeight: CGFloat, duration: TimeInterval, delay: TimeInterval) // provides an animation with duration and delay associated with the case func getAnimation() -> TableCellAnimation { switch self { case .fadeIn(let duration, let delay): return TableAnimationFactory.makeFadeAnimation(duration: duration, delayFactor: delay) case .moveUp(let rowHeight, let duration, let delay): return TableAnimationFactory.makeMoveUpAnimation(rowHeight: rowHeight, duration: duration, delayFactor: delay) case .moveUpWithFade(let rowHeight, let duration, let delay): return TableAnimationFactory.makeMoveUpWithFadeAnimation(rowHeight: rowHeight, duration: duration, delayFactor: delay) case .moveUpBounce(let rowHeight, let duration, let delay): return TableAnimationFactory.makeMoveUpBounceAnimation(rowHeight: rowHeight, duration: duration, delayFactor: delay) } } // provides the title based on the case func getTitle() -> String { switch self { case .fadeIn(_, _): return "Fade-In Animation" case .moveUp(_, _, _): return "Move-Up Animation" case .moveUpWithFade(_, _, _): return "Move-Up-Fade Animation" case .moveUpBounce(_, _, _): return "Move-Up-Bounce Animation" } } }
Мы определили перечисление TableAnimation с четырьмя случаями для четырех анимаций вместе со связанными значениями, которое предоставляется методам Animation Factory.
Перечисление также имеет две функции —
- GetAnimation возвращает анимацию из animationFactory на основе случаев перечисления и связанных с ней значений.
- GetTitle возвращает заголовок анимации на основе случаев перечисления.
Давайте напишем код для ViewController —
Начнем с соединения аутлетов представления во ViewController — (У нас так же есть аутлет функции кнопки который мы определим позже)
import UIKit class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { // MARK:- outlets for the viewController @IBOutlet weak var tableView: UITableView! @IBOutlet weak var button1: UIButton! @IBOutlet weak var button2: UIButton! @IBOutlet weak var button3: UIButton! @IBOutlet weak var button4: UIButton!
Добавьте переменные для ViewController —
// MARK:- variables for the viewController var colors = [UIColor.systemRed, UIColor.systemBlue, UIColor.systemOrange, UIColor.systemPurple,UIColor.systemGreen] var tableViewHeaderText = "" /// an enum of type TableAnimation - determines the animation to be applied to the tableViewCells var currentTableAnimation: TableAnimation = .fadeIn(duration: 0.85, delay: 0.03) { didSet { self.tableViewHeaderText = currentTableAnimation.getTitle() } } var animationDuration: TimeInterval = 0.85 var delay: TimeInterval = 0.05 var fontSize: CGFloat = 26
Здесь краткое описание для каждой переменной —
- Colors — цвета, которые мы представим в TableView.
- TableViewHeaderText — определяет заголовок заголовка TableView.
- CurrentTableAnimation — это тип значения модели перечисления, который мы определили ранее, он устанавливает переменную TableViewHeaderText при изменении самого перечисления.
- AnimationDuration — определяет продолжительность анимации ячейки.
- Delay — определяет задержку между анимацией каждой ячейки.
- FrontSize — определяет размер символов для кнопок.
Далее, зарегистрируйте TableView и установите метод жизненого цикла ViewController —
Мы зарегистрировали пользовательский класс UITableViewCell с нашим TableView и установили delegate и dataSource для viewController, мы установили символ button1, чтобы он отображался как выбранный, а также мы асинхронно перезагружаем данные для отображения анимации.
Затем, давайте установим методы delegate и dataSource TableView во ViewController —
// MARK:- lifecycle methods for the ViewController override func viewDidLoad() { super.viewDidLoad() self.colors.append(contentsOf: colors.shuffled()) // registering the tableView self.tableView.register(UINib(nibName: TableAnimationViewCell.description(), bundle: nil), forCellReuseIdentifier: TableAnimationViewCell.description()) self.tableView.delegate = self self.tableView.dataSource = self self.tableView.isHidden = true // set the separatorStyle to none and set the Title for the tableView self.tableView.separatorStyle = .none self.tableViewHeaderText = self.currentTableAnimation.getTitle() // set the button1 as selected and reload the data of the tableView to see the animation button1.setImage(UIImage(systemName: "1.circle.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: fontSize, weight: .semibold, scale: .large)), for: .normal) DispatchQueue.main.asyncAfter(deadline: .now()) { self.tableView.isHidden = false self.tableView.reloadData() } }
Мы добавили стандартные методы для инициализации TableView, давайте вкратце рассмотрим их —
- numberOfRowsInSection определяет количество отображаемых ячеек TableView.
- heightForRowAt определяет высоту ячеек TableView
- cellForRowAt инициализирует ячейку для indexPath, назначает ей цвет и возвращает ячейку в TableView.
- viewForHeaderInSection определяет представление для TableHeader, мы настроили его для отображения метки со значением, полученным из перечисления.
- heightForHeaderInSection определяет высоту заголовка таблицы.
- willDisplay является наиболее важным методом в этом руководстве, мы получаем анимацию из перечисления currentAnimation, инициализируем класс TableViewAnimator этой анимацией, а затем анимируем ячейку, вызывая метод animate аниматора.
Наконец, давайте добавим код для взаимодействия кнопок, каждая кнопка должна перезагружать таблицу со значением, полученным из созданного нами перечисления Table —
// delegate functions for the tableView func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return colors.count } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return TableAnimationViewCell().tableViewHeight } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { if let cell = tableView.dequeueReusableCell(withIdentifier: TableAnimationViewCell.description(), for: indexPath) as? TableAnimationViewCell { // set the color of the cell cell.color = colors[indexPath.row] return cell } fatalError() } // for displaying the headerTitle for the tableView func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let headerView = UIView(frame: CGRect.init(x: 0, y: 0, width: tableView.frame.width, height: 42)) headerView.backgroundColor = UIColor.systemBackground let label = UILabel() label.frame = CGRect(x: 24, y: 12, width: self.view.frame.width, height: 42) label.text = tableViewHeaderText label.textColor = UIColor.label label.font = UIFont.systemFont(ofSize: 26, weight: .medium) headerView.addSubview(label) return headerView } func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 72 } // func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { // fetch the animation from the TableAnimation enum and initialze the TableViewAnimator class let animation = currentTableAnimation.getAnimation() let animator = TableViewAnimator(animation: animation) animator.animate(cell: cell, at: indexPath, in: tableView) }
Примечание. Все четыре кнопки должны быть назначены одной функции выхода, в этом руководстве я назначил ее функции animationButtonPressed.
Поскольку мы хотим, чтобы только одна кнопка отображалась выбранной за раз, мы сначала назначаем всем кнопкам символ круга, удаляя заливку с ранее выбранной кнопки.
Теперь, на основе тегов, назначенных кнопке, случай переключателя помогает установить символ этой конкретной кнопки как заполненный, и, аналогично, переменная currentTableAnimation также устанавливается соответствующим образом —
- Button1 применяет анимацию постепенного появления к TableViewCells.
- Button2 применяет анимацию перемещения вверх к TableViewCell.
- Button3 применяет анимацию Move-Up-Fade к TableViewCells.
- Button4 применяет анимацию Move-Up-Bounce к TableViewCells.
Это все, теперь, когда вы запустите приложение, вы должны получить восхитительную анимацию в TableView, и анимация меняется при нажатии другой кнопки.
Вот конечный результат, анимируйте TableView, нажимая кнопки —
. . .
Ресурсы
. . .
Заключение
Давайте повторим что мы выучили сегодня.
Мы начали с добавления компонентов, необходимых для анимации TableView, в файл Main.Storyboard.
Затем, создали настраиваемый класс UITableViewClass и добавили компоненты в XIB файл.
Затем, мы создали TableViewAnimator класс, который анимирует TableView, помните, о создании отдельного класса для каждой анимации. Мы также создали перечисление TableAnimationFactory, где определили 4 анимации.
Затем, мы создали перечисление TableAnimation, чтобы сгруппировать анимацию и заголовок для TableViews в отдельных случаях путем создания функций.
Наконец, мы написали код для ViewController, мы настроили TableView, мы добавили функцию выхода для кнопок и назначили ей анимацию для установки анимации TableView.
Спасибо, что прочитали эту статью. Надеюсь увидеть вас снова в следующей статье!