Советы и рекомендации по реализации масштабируемой и продуманной системы дизайна во Flutter

Nielsen Norman Group (консалтинговая компания, занимающаяся исследованиями UX) определяет систему дизайна следующим образом:

«Система дизайна — это набор стандартов для управления дизайном в масштабе за счет уменьшения избыточности при создании общего языка и визуальной согласованности на разных страницах и каналах».

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

Возможно, вы слышали о таких дизайн-системах, как Bootstrap и Ant Design для веб-сайтов, или, может быть, Design Language System от AirBnB. Даже если они не кричат ​​об этом с крыш, компании, успешные в дизайне, скорее всего, имеют дизайн-систему. Это позволяет им сосредоточиться на идентичности и функциональности своих приложений, не задумываясь об отдельных элементах, таких как кнопки, баннеры, текст и т. д.

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

Мы не будем обсуждать, как возникает дизайн-система, кто разрабатывает стандарты и как они документируются. Вместо этого предположим, что у нас есть четко определенная система дизайна, и назовем ее MyDesign. Наша работа состоит в том, чтобы создать компоненты MyDesign во Flutter и сделать так, чтобы они точно соответствовали стандартам, которые определяет наша система проектирования. Мы сосредоточимся конкретно на наборе виджетов кнопок:

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

Именование важно

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

Старайтесь использовать для своих виджетов те же имена, что и дизайнеры при описании компонентов. Это гарантирует отсутствие недопонимания при работе между проектированием и реализацией. Примените эту методологию и к настройке ваших виджетов. Если кнопка имеет «начальный» и «конечный» значок вместо «левого» и «правого», используйте ту же терминологию в полях вашего класса виджетов. В случае с кнопками MyDesign мы можем видеть, что они отражают кнопки с заливкой Материалом (приподнятые) и контуры, но называются первичными и вторичными. Наша реализация должна учитывать эту схему именования.

Реализации дизайн-систем часто живут независимо от приложений, которые они поддерживают. Это выгодное разъединение, так что бизнес-логика не перетекает в реализацию проекта, и ваша библиотека может быть повторно использована в качестве зависимости между несколькими приложениями-потребителями. Я обнаружил, что из-за этого префикс для виджетов, предоставляемый системой дизайна, также полезен. MyButton вместо Button помогает различать, какие виджеты в приложении являются локальными, а какие нет, а также позволяет избежать конфликтов имен со многими виджетами, предоставляемыми Flutter и другими зависимостями приложений.

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

Токены дизайна — это «примитивы» системы дизайна — постоянные значения, повторно используемые во всех компонентах и ​​определенных стандартах. Такие вещи, как цвета, интервалы, стили текста и значки, часто включаются в системы дизайна в качестве «токенов» и являются хорошими кандидатами для определения независимо от виджетов, которые их используют. Материальный дизайн уже делает это с классами Colors и Icons, а также textTheme объекта Theme по умолчанию, содержащего предопределенные текстовые обработки, такие как стили основного текста и заголовков.

Использовать композицию

Flutter построен на агрессивной компонуемости, и ваша библиотека дизайн-системы должна быть такой же. Воспользуйтесь обширным каталогом виджетов Material Design и Cupertino от Flutter и настройте их в соответствии со спецификациями вашей системы. Это абстрагирует стиль от всех мест, где будут использоваться ваши виджеты. Избегайте повторения кода в виджетах, создавая меньшие виджеты, которые вы можете объединять в другие. С кнопками MyDesign мы создадим кнопки Материала в качестве основы. В более сложных системах у вас могут быть собственные базовые компоненты, которые могут быть объединены в несколько других.

Уменьшить поверхность API

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

Если вы используете виджет Material и стилизуете его для своего дизайна, вам, вероятно, не нужны все конфигурации, которые позволяет виджет. Виджеты материалов предназначены для гибкой настройки, но ваши виджеты могут быть не такими. Уменьшите эти параметры!

Некоторые виджеты, такие как ElevatedButton, чрезвычайно гибки в том, что может быть передано как дочерний элемент (требуется любой Widget). В MyDesign кнопки допускают только текст и значки в качестве дочерних элементов, поэтому мы перепечатаем поля нашего виджета, чтобы гарантировать, что принимаются только допустимые значения, и позволить функции сборки абстрагироваться от сложностей построения внутренних элементов кнопки.

Используйте Enums для обеспечения допустимых входных данных

Этот совет является продолжением приведенной выше рекомендации. Во многих случаях типы полей виджета могут допускать значения, которые не соответствуют правилам вашей дизайн-системы. Например, кнопки MyDesign позволяют использовать только подмножество цветов из палитры бренда. Вместо того, чтобы наш виджет принимал параметр типа Color (и, таким образом, разрешал неправильно окрашенные кнопки), мы создадим перечисление, которое представляет и ограничивает конфигурацию теми, которые разрешены.

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

Наследовать стили

Всегда полезно не задавать жестко заданные значения. В основном мы позаботились об этом, разделив токены дизайна на константы. Тем не менее, использование MyColors.blue вместо Color(0xff0000ff) во всем нашем коде может привести к ненужным ограничениям нашей системы дизайна. В то время как наши токены позволяют редактировать значения в единственном месте, если система дизайна нуждается в изменениях, что, если нам нужна совершенно новая тема? Это обычная практика со светлыми и темными темами в приложениях.

Статические постоянные переменные не могут решить предпочтения пользователя в теме. Таким образом, как и в случае с Material design, используйте наследование стилей из глобального Theme, изменяя свойства, которые идут вместе с ним, или создавая расширения темы.

Используйте именованные конструкторы

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

Глядя на наши первичную и вторичную кнопки MyDesign, мы знаем, что в построении внутренних компонентов используется повторно код, но нам все равно понадобятся Материалы ElevatedButton и OutlineButton соответственно. Мы могли бы создать два отдельных виджета MyPrimaryButton и MySecondaryButton и извлечь виджет для создания дочерних элементов. В качестве альтернативы мы могли бы иметь один виджет с именованными конструкторами, MyButton.primary и MyButton.secondary.

Эти конструкторы могут устанавливать приватное поле, которое говорит нам, что делать в нашем методе сборки. Этот подход становится более ценным для нескольких виджетов, поскольку логика и метод сборки усложняются (совместное использование кода проще, чем координация взаимодействия нескольких виджетов). Также может быть полезно «группировать» варианты виджетов таким образом для семантических целей. При автозавершении кода IDE ввод MyButton. дает «каталог» доступных вариантов — преимущество, недоступное при использовании мультивиджетного подхода.

Заключение

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

Дополнительное чтение

Чрезвычайно важно, чтобы дизайн-системы были гибкими для разных устройств. Ознакомьтесь с моей статьей Отзывчивая верстка во Flutter.

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