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

Реализация наших функций на основе дизайнов

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

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

Возьмем в качестве примера 3 разных представления, принадлежащих приложению Facebook для iOS.

Давайте подумаем, как разработчик, и начнем разбивать представление на более мелкие компоненты. Например, можно сказать:

  • Представление даты рождения, состоящее из двух разных UILabels, выровненных по вертикали: одна вверху с полужирным шрифтом, а другая внизу - с обычным шрифтом. Оба UILabel используют всю ширину и выравниваются по левому краю.
  • Просмотр любимой музыки, состоящий из UIImageView вверху по центру и UILabel по центру, которые используют всю ширину.
  • Представление запроса на добавление в друзья, состоящее, вероятно, из двух UILabels вверху, первый - с однострочным шрифтом и жирным шрифтом, второй - многострочным. Затем, вверху слева, UIImageView с правым заполнением, и, наконец, у нас есть еще один UILabel, который использует оставшуюся ширину.

Это может быть подход, применяемый кем-то, кто не разбирается в мощи некоторых элементов пользовательского интерфейса. Таким образом, это означает, что, скорее всего, разработчик создаст 3 разных макета для реализации 3 разных представлений. Он наверняка будет работать, но в результате у него закончится много кода и, скорее всего, разочарованный разработчик.

Какие есть альтернативы?

В этом случае нам очень повезло, самое простое решение - лучшее. Ему просто нужно одно единственное представление, состоящее из единственного UILabel:

Раскрытие возможностей NSAttributedString

Каждый отдельный UILabel содержит свойство с именем attributedText, это свойство ожидает получить объект типа NSAttributedString.
После официального Apple документация имеем:

Объект NSAttributedString управляет символьными строками и связанными наборами атрибутов (например, шрифтом и кернингом), которые применяются к отдельным символам или диапазонам символов в строке. Связь символов и их атрибутов называется строкой с атрибутами. Два открытых класса кластера, NSAttributedString и NSMutableAttributedString, объявляют программный интерфейс для строк с атрибутами только для чтения и изменяемых строк с атрибутами соответственно.

По сути, NSAttributedString - лучший вариант для создания форматированного текста. Легко настраивается и открывает сотни возможностей.

Упростите макет

Отображение просмотров - одна из самых дорогих операций в iOS-разработке. Вот почему важно повторно использовать элементы во время выполнения и уменьшить сложность макета.

С решением, которое мы только что выбрали, у нас есть беспроигрышный вариант. Мы собираемся использовать UITableViewCell, который по своей природе является повторно используемым компонентом, а затем внутри у нас будет один UILabel, который заполняет родительский контейнер с помощью AutoLayout.

Прежде чем продолжить, настоятельно рекомендую вам ознакомиться с моей предыдущей статьей Ускорьте разработку iOS: парадигма модулей (часть 1). Потому что с этого момента и до конца мы должны следовать и использовать ранее описанные здесь примеры.

Повторно используйте один и тот же макет вместе с несколькими представлениями

Несмотря на то, что выглядит невероятно, чтобы выполнить требования исходного дизайна, используя преимущества NSAttributedString, нам просто нужно установить два разных значения: backgroundColor и myLabel.attributedText.

Чтобы упростить настройку представления, давайте создадим конкретную модель, которая будет содержать всю информацию, запрашиваемую из макета представления. Это когда Decorator начинают играть.

Декоратор

Декоратор похож на простой ViewModel объект, который используется для «украшения вида» (не путайте с шаблоном декоратора).
Как мы делаем вид, что повторно используем один и тот же макет для создания трех разных представлений, мы собираемся вызвать наш класс Decorator, CommonAttributedDecorator.

Как вы могли заметить, CommonAttributedDecorator просто возвращает 2 значения: backgroundColor и attributedTitle. Точно те же значения, которые требовались для макета основного вида.

Следующим шагом является подготовка общего макета представления, в котором будет использоваться декоратор. Нам просто нужен UITableViewCell под названием AttributedCell:

Пока все выглядит так просто. Но подождите ...
Где сложность, которую требуют представления?

Ответ прост - все находится в подклассах CommonAttributedDecorator. Там мы переопределим методы backgroundColor и attributedTitle для соответствия дизайну.

Переместите логику как можно больше в декоратор

Декораторы должны содержать всю логику дизайна, например:
- Цвет / размер шрифта
- Иконки
- Выравнивания
- Ограничение значений
И они также включают некоторые бизнес-логика, например переводы или элементы, которые отображаются / скрываются в зависимости от некоторых бизнес-условий.

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

На изображении выше показаны только общедоступные функции, однако, как вы можете заметить, мы вызываем некоторые внутренние функции как mainAttributedInfo, attributedBreakLine, descAtreibutedInfo и lightColor. Они описаны в том же файле, что и частное расширение:

Здесь у нас есть несколько свойств, в которых мы определяем всю бизнес-логику и логику проектирования с максимальным сжатием NSAttributedString.
Пожалуйста, ознакомьтесь с методами, и вы быстро поймете, как работает NSAttributedString.

То же самое относится к просмотру избранной музыки с помощью FavoriteMusicAttributedDecorator.

И дополнительные частные объекты:

И, наконец, представление запроса на добавление в друзья, в котором создается RequestFriendsAttributedDecorator:

И он владеет частной собственностью.

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

Окончательные результаты

Мы собираемся реализовать новый Модуль с одним многоразовым AttributedCell. Это AttributedModule.

Как вы могли заметить, мы настраиваем AttributedCell представление, передаваемое по параметру, используемому в декораторе:
attributedCell.configure(decorator: decorator)

Легко, правда? с помощью всего лишь одного метода мы настраиваем, какое представление будет отображаться.

Наконец, вот как выглядят 3 разных ряда

Выводы

Это может показаться странным, но использование декораторов просто имеет преимущества:

  • Делает в основном ваши взгляды менее сложными
  • Делает представления более универсальными и пригодными для повторного использования
  • Уменьшает количество вложенных просмотров
  • Повышает производительность
  • Сгруппируйте логику дизайна по однотипным объектам.
  • Сохраняет строки кода
  • Позволяет проводить модульное тестирование содержимого ваших представлений

Подводя итог, можно сказать, что это повышает качество, гибкость, надежность и тестируемость вашего кода.

Если вы хотите иметь те же примеры, которые мы использовали здесь, или даже более сложные примеры - у меня есть дополнительный репозиторий. Он содержит несколько модулей, и некоторые из них похожи на компоненты, используемые в приложениях WhatsApp и Facebook. Просто скачайте его и нажмите кнопку воспроизведения, вы не пожалеете:



Если вы попробуете Декораторы, я хотел бы услышать об этом. Или, эй, если ты думаешь, что в этом нет смысла, дай мне знать тоже. Комментарии приветствуются, не стесняйтесь!

Как вы могли заметить, это вторая часть серии Ускорьте разработку iOS (здесь у вас первая). Вскоре я создам третью часть, где разорву на пределе возможности снэпшот-тестирования. Будьте на связи!