Segmented control что это
Несколько лет назад мы создали сегментированный компонент для дизайн-системы Lyft Product Language (LPL). Возможно, вы читали наше руководство по проектированию и использованию элементов управления выбором. Однако, недавно мы посмотрели на показатели внедрения и использования наших компонентов, и обнаружили, что очень немногие команды использовали сегментированный элемент управления при создании продуктов и функций 😔.
Мы считаем, что по крайней мере два продукта или функции должны использовать компонент, чтобы он мог быть включен в дизайн-систему. Компоненты, относящиеся к продуктам и функциям, находятся в собственных дочерних библиотеках, которые наследуют атрибуты дизайн-системы LPL. Сегментированные элементы были опасно близко к удалению из системы. К счастью, мы решили более внимательно изучить причину проблемы и в итоге улучшили всю экосистему элементов управления выбором.
Segmented Control своими руками, как в iOS 13.0 и выше
В iOS 13 обновили Segmented Control, но для тех кто не может обновить Xcode, он просто не доступен. Вот я и решил написать, как можно быстро сделать самому такой же Segmented Control.
Поехали!
Первым делом переходим в Storyboard. Размещаем на нашем ViewController элемент View.
Закрепляем его констрейнтами как вам угодно и в каком месте он вам нужен.
Закрашиваем фон и ставим галочку clip to Bounds.
Берем еще одно View и размещаем его внутри нашего первого View. Только обязательно посмотрите что он был внутри вашего первого View. Он должен быть размещен в лестничном порядке.
Далее закрепляем его констрейнтами с отступом в 2 pix со всех сторон.
И он будет размещен внутри вашего первого вью как на фото ниже.
Далее выделяем наш белый View который внутренний. Выбираем leading и traling констрейн, и меняем у них Priority на 750.
Теперь создаем у данного View еще два констрейнта с лева и справа с отступом 0 pix
Так же переходим в редактирование данных констрейнтов которые мы создали только что и меняем у них Priority = 900 и закрепляем их не от краев нашего серого View, а ставим относительно центра и если вы все сделаете правильно то ваш белый View соберется линией в центре.
Теперь выбираем два Button и размещаем их внутри серого вью, но они должны быть по иерархии в самом внизу что бы текст их далее не перекрывался нашим белым вью когда мы будем его двигать. Закрепляем наши кнопки по центру относительно своей половины.
Все. Tеперь соединяем наши элементы с сториборд с ViewController.
Серый View я назвал — fonView.
Белый View назвал — blockView.
Так же две кнопки buttonOne и buttonTwo и создал у них action.
Еще в наш код перетягиваем два констрейнта которые мы сделали с priority 750. Назовем их:
В viewDidLoad мы прописываем только закругление наших View и один констрейн делаем равным priority 950 что бы белое вью не было в середине как линия, а выглядела как выбранный сегмент.
Финишная прямая. В action button мы прописываем такой код. суть в том что мы меняем наши приоритеты и вью увеличивается на нужные размеры и делаем обновление наших констрейнтов анимированно.
Segmented Control своими руками, как в iOS 13.0 и выше
В iOS 13 обновили Segmented Control, но для тех кто не может обновить Xcode, он просто не доступен. Вот я и решил написать, как можно быстро сделать самому такой же Segmented Control.
Поехали!
Первым делом переходим в Storyboard. Размещаем на нашем ViewController элемент View.
Закрепляем его констрейнтами как вам угодно и в каком месте он вам нужен.
Закрашиваем фон и ставим галочку clip to Bounds.
Берем еще одно View и размещаем его внутри нашего первого View. Только обязательно посмотрите что он был внутри вашего первого View. Он должен быть размещен в лестничном порядке.
Далее закрепляем его констрейнтами с отступом в 2 pix со всех сторон.
И он будет размещен внутри вашего первого вью как на фото ниже.
Далее выделяем наш белый View который внутренний. Выбираем leading и traling констрейн, и меняем у них Priority на 750.
Теперь создаем у данного View еще два констрейнта с лева и справа с отступом 0 pix
Так же переходим в редактирование данных констрейнтов которые мы создали только что и меняем у них Priority = 900 и закрепляем их не от краев нашего серого View, а ставим относительно центра и если вы все сделаете правильно то ваш белый View соберется линией в центре.
Теперь выбираем два Button и размещаем их внутри серого вью, но они должны быть по иерархии в самом внизу что бы текст их далее не перекрывался нашим белым вью когда мы будем его двигать. Закрепляем наши кнопки по центру относительно своей половины.
Все. Tеперь соединяем наши элементы с сториборд с ViewController.
Серый View я назвал — fonView.
Белый View назвал — blockView.
Так же две кнопки buttonOne и buttonTwo и создал у них action.
Еще в наш код перетягиваем два констрейнта которые мы сделали с priority 750. Назовем их:
В viewDidLoad мы прописываем только закругление наших View и один констрейн делаем равным priority 950 что бы белое вью не было в середине как линия, а выглядела как выбранный сегмент.
Финишная прямая. В action button мы прописываем такой код. суть в том что мы меняем наши приоритеты и вью увеличивается на нужные размеры и делаем обновление наших констрейнтов анимированно.
Решайте одну проблему за раз
Первую группу стилистических несоответствий устранить было относительно несложно. Мы переработали элемент управления, чтобы он был менее похож на таблетку, кнопку переключения, и стал больше похож на визуально облегченные поля ввода.
Новые, легкие стили сегментированных элементов управления
Одна из главных причин, по которой продуктовые и функциональные группы создали свои собственные компоненты, заключалась в том, что наши не были достаточно гибкими, чтобы адаптироваться к широкому спектру сценариев использования. Поэтому мы также представили 3 новых стилистических варианта компонента:
- Сподробным текстом – для случаев, когда дополнительная информация помогает пользователям лучше понимать варианты и принимать решения.
- Иконка – только, когда для каждого варианта иконки достаточно контекста, чтобы передать смысл.
- Основной текст – когда сегментированный элемент управления является единственным или основным действием на экране.
Чтобы замкнуть цикл и стимулировать принятие, мы заменили кастомные компоненты на всех экранах, которые мы собрали во время аудита, и продемонстрировали новые варианты. Аналогично тому, как лучше использовать настоящий текст и данные вместо автоматически сгенерированного Lorem Ipsum, мы сочли более эффективным использование реальных экранов для стресс-тестирования нашего компонента.
Тем временем на предмет семантических расхождений мы просмотрели другие системы… и обнаружили больше расхождений 🤦♀️. Во-первых, нет единого мнения о том, как назвать этот паттерн. Помимо сегментированного элемента управления (segmented control), мы видели, что в разных системах оно называется группой кнопок (button group), переключателями (toggle buttons), радио-кнопкой (radio bar) или переключателем контента (content switch). И для каждого нового имени есть разные правила использования. Оказывается, это не просто проблема соглашения о платформе, это мета-проблема для всех дизайн-систем. Неудивительно, что мы видели так много различных его вариантов в наших специализированных командах!
Излишне говорить, что решение проблем межсистемной согласованности выходило далеко за рамки этого проекта. Поэтому вместо этого мы сосредоточились на том, чтобы сделать нашу собственную систему максимально ясной и внутренне согласованной. Для обработки сценариев использования фильтрации и навигации мы создали новый компонент в системе (вкладки!), а также обновили наши деревья решений вместе с определениями компонентов, чтобы сделать различие более четким. Чтобы еще больше усилить семантическую разницу между сегментированными элементами управления и вкладками, мы сделали состояния выбора, формы контейнеров и направляющие движения разными.
Понятные и последовательные отличия
Наше предыдущее определение сегментированного элемента управления в значительной степени заимствовано из определения Apple, в котором буквально указано, что представляет собой компонент. Но «что» не помогает дизайнерам принимать решения. Теперь мы подчеркиваем «почему» и «как»:
Сегментированные элементы управления позволяют пользователям делать один выбор из набора в 2–5 параметров в качестве общей альтернативы радио-кнопкам и раскрывающимся меню. Они наглядно представляют все доступные варианты для пользователей и просты в использовании на мобильных устройствах.
- Используйте их поверх других средств выбора, чтобы снизить когнитивную нагрузку.
- Не используйте их для фильтрации или навигации по содержимому (вместо этого используйте вкладки).
Вывод
Обновление документации – это один момент, но нам все еще нужно было максимально упростить дизайнерам использование обновленного компонента системы. Мы хотели избежать запуска потенциальных критических изменений, просто меняя символы в Figma. Вместо этого мы отказались от старого компонента, как это было предложено в замечательной статье Onfido об устаревших компонентах в дизайн-системах Figma. Для нас это означало:
- Переименование страницы со старым компонентом.
- Перемещение страницы со старым компонентом в раздел «DeprecatedDungeon» нашей библиотеки.
- Добавление очевидного визуального наложения ко всем вариантам старого компонента, в комплекте с эмодзи призрака 👻, за который проголосовала наша команда дизайнеров.
После передачи старого компонента мы могли, наконец, считать эту проблему решенной.
Изгнан, но не забыт
Пока существует централизованная система, будут команды, которые отклоняются от нее. Очень часто, как системные администраторы, мы стремимся уменьшить и устранить эти отклонения. В этом случае мы могли бы удалить сегментированный элемент управления из LPL, потому что он не использовался. Тем не менее, когда мы исследовали, почему так много команд решили создавать кастомные компоненты вместо использования системных, мы получили более разнообразную, более надежную, удобную и лучше определенную экосистему паттернов выбора. Что касается мета-проблемы, если ваша команда называет этот компонент как-то иначе или думает о его использовании иначе, чем мы, давайте поговорим об этом!
Segment routing: как и почему
Операторы связи и большие корпорации, оценившие все достоинства MPLS, вынуждены мириться с несколькими control plane протоколами в своей сети. IGP+LDP стал де-факто стандартом в ядре сети. Вместе с этим известно, что протокол OSPF расширяем за счет opaque LSA, протокол IS-IS уже много лет успешно расширяется добавлением новых TLV. А что если добавить MPLS метку непосредственно в IGP? И можно ли избавиться от не слишком гибкого RSVP? Приверженцев оптимизации прошу под кат.
Избавляемся от LDP
Рабочая группа SPRING предложила переложить функции протоколов распространения меток на IGP, а LSP строить сегментами. Сегмент представляет собой часть (или весь) LSP до конкретного маршрутизатора. Для назначения меток используется выделенный диапазон, чтобы не пересекаться с классическими протоколами. Его называют SRGB — segment routing global block. Этот блок может отличаться на разных устройствах, хотя при возможности лучше использовать одинаковый, чтобы окончательно не запутаться. Однако метка для достижения конкретного PE при этом должна быть уникальной. При этом метка на всем сегменте не изменяется. Важно понимать, что операция swap производится в любом случае, просто in и out метки совпадают. По умолчанию устройства на платформе IOS XR используют значения 16000-23999 для SRGB. И, поскольку блоки могут отличаться, информация о них анонсируется через IGP.
С блоком понятно. Но как маршрутизаторы приходят к соглашению о значению метки для определенного FEC? На каждом устройстве должен быть сконфигурирован уникальный SID — segment identifier. Существуют Node SID и Adjacency SID, о последних — чуть ниже. Для определения метки, которая будет закреплена за лупбэком устройства, к нижней границе SRGB прибавляется Node SID. Например, если SRGB начинается с 16000, а устройству присвоен SID 5, то метка для достижения лупбэка устройства будет равна 16005. Эту метку будут использовать все устройства по пути следования (swap 16005 -> 16005).
Почему вдруг речь пошла о лупбэках? Дело в том, что SR — это технология для построения пути до конкретного PE устройства. Другими словами, речь идет о транспортных метках. А достичь PE устройство — значит достичь его лупбэка. Распространение и назначение сервисных меток, будь то L2VPN, L3VPN или другие технологии, не изменяется. Все тот же MP-BGP будет необходим для построения сервисов, все те же сервисные метки будут располагаться внизу стека.
Чуть выше я сказал, что SID устройства должен быть уникальным. Так вот, это наглая ложь. Adjacency SID имеет локальное значение. Маршрутизатор генерирует Adjacency SID для каждого SR соседа автоматически, и значение никак не пересекается с SRGB. Конфигурировать в этом случае ничего не нужно. Как и все остальное, такие метки распространяются протоколом IGP. Это дает возможность передавать трафик через определенный интерфейс. Как указать интерфейс, если метка может не быть уникальной? Здесь все просто: для этого используется стек меток, где верхняя метка — Node SID, а нижняя — Adjacency SID.
Избавляемся от RSVP
LDP всем хорош, вот только следует пути, который выбрал IGP, и полосу резервировать не умеет. При необходимости построить путь передачи трафика отличный от того, что выбрал IGP, на помощь приходит RSVP-TE с его explicit paths. В случае с построением пути, отличным от лучшего по мнению IGP, SR может заменить функционал RSVP прямо из коробки: достаточно просто создать стек меток, который полностью опишет путь. Например, если нам нужно, чтобы трафик отправлялся через Router A до Router B, в стеке транспортных меток будет сначала SID Router A, а затем SID Router B.
Признаться, с точки зрения конфигурации мало что изменяется: в explicit path используются все те же IP адреса. И сразу ответ на часто возникающий вопрос: да, оверхед увеличивается. Если необходимо точно определить путь из десяти маршрутизаторов, то в стеке будет 10 меток. Однако такие сценарии на практике встречаются очень редко. Обычно хватает нескольких меток, чтобы решить конкретную задачу.
А полосу-то как резервировать? С этим пока сложно. Сейчас нет проблем с тем, чтобы запустить CSPF. Проблема заключается в том, что для резервирования полосы пропускания необходимо состояние на маршрутизаторе, которое описывает значение зарезервированной ПП для каждого LSP. Поэтому концепт резервирования полосы требует введения понятия PCE.
PCE — path computation element — это контроллер, который общается с маршрутизаторами по протоколу PCEP. Этот контроллер может рассчитывать TE туннели с использованием CSPF, в том числе с атрибутом bandwidth. Замечу, что PCE и SR — это не единственная существующая комбинация. С не меньшим успехом PCE может работать с RSVP, LDP и даже статически назначать метки. В общем случае задача PCE заключается в том, чтобы установить сразу forwarding state на устройство через протокол PCEP.
Разумеется, для расчета пути PCE должен знать существующую топологию. Рассказать PCE о топологии можно сделав его частью топологии, т. е. подключив его к IGP домену. Альтернативный вариант — BGP-LS сессия с контроллером.
PCE способен отслеживать текущую загрузку интерфейсов и перестраивать путь прохождения туннелей, если это требуется. Другими словами, этот элемент можно назвать SDN контроллером поверх существующей MPLS сети. Однако даже краткое описание PCE — это тема как минимум отдельной статьи. Поэтому я оставлю здесь ссылки на популярные open source проекты, которые в том или ином виде поддерживают PCEP: это ONOS и ODL — а мы вернемся к SR.
Определение проблемы
Мы начали с первых принципов и спросили: «Что такое сегментированный элемент управления?» Apple утверждает, что они представляют собой «линейный набор из двух или более сегментов, каждый из которых функционирует как взаимоисключающая кнопка». Они считают, что для перехода между различными представлениями можно использовать сегментированные элементы управления. Google не согласен с использованием сегментированных элементов управления для навигации и говорит, что иногда можно выбрать несколько сегментов – в отличие от Apple. Google также не считает, что сегментированные элементы управления – это элементы управления выбором 😐.
При проектировании взаимозаменяемой дизайн-системы для iOS, Android и Web интерфейсов, из-за подобных противоречивых принципов платформ, сложно определить, какой вариант будет наиболее знаком пользователям на всех устройствах.
Когда мы впервые создали наш сегментированный компонент управления в LPL, мы не учли эту путаницу в условных обозначениях. Мы оптимизировали систему для внутренней согласованности, выбрав в соответствии с визуальным стилем наших кнопок-переключателей в виде таблеток.
Предыдущие элементы управления выбором
Теоретически мы думали, что кнопки-переключатели и сегментированные элементы управления могут часто появляться в одних и тех же контекстах, поскольку они функционально аналогичны флажкам и радио-кнопкам. На практике, однако, дизайнеры и разработчики взяли дело в свои руки и создали всевозможные варианты настраиваемых сегментированных элементов управления. При аудите наших продуктов мы обнаружили 14 отдельных сегментированных компонентов в 10 различных продуктах. Очевидно, наш существующий компонент не отвечал потребностям пользователей нашей дизайн-системы. Нам не нужно было удалять сегментированный элемент управления из системы, нам нужно было сделать его более качественным.
При ближайшем рассмотрении мы увидели, что кастомные элементы отличаются от сегментированного элемента управления дизайн-системы одним из двух способов:
- Стилистические различия: элементы управления с разными цветами выделения и фона, формами контейнеров и / или стилями текста.
- Семантические различия: элементы управления, используемые для навигации или фильтрации контента (как позволяет Apple) вместо выбора, как предполагалось.
Что в итоге?
Все выглядит очень красиво и оптимистично, но где же это применить? Давайте рассмотрим несколько сценариев.
1. Замена протоколу LDP.
Мы разобрались, что заменить RSVP без PCE будет затруднительно, когда используется bandwidth reservation. Поэтому как полноценную замену RSVP без дополнительных элементов в сети SR рассматривать не станем. А что касается LDP, то в теории этот протокол можно выключить и распространять транспортные метки через IGP. Однако этот сценарий едва ли приносит достаточно преимуществ, учитывая риски, на которые придется идти при редизайне сети. К тому же не всегда каждое устройство в сети поддерживает SR. Это можно решить с помощью дополнительной конфигурации, когда несколько устройств являются границей между SR и LDP доменом. Однако факт наличия такой конфигурации заставляет еще больше задуматься о плюсах и минусах решения. Говоря откровенно, сейчас нет причин заменять LDP на SR просто для того, чтобы заменить.
2. Topology independent LFA.
LFA или IP FRR не работает в произвольных топологиях. Например, в кольцевой топологии маршрутизатор не сможет рассчитать запасной путь, поскольку любой путь приведет к петле. Однако используя инкапсуляцию в MPLS, трафик можно сбросить не только соседу, но и удаленному устройству. Здесь SR имеет практический смысл. Разумеется, эту же задачу можно решить с помощью RSVP, но решение с SR выглядит более элегантным.
В качестве примера представьте упомянутую кольцевую топологию, где OSPF cost между всеми маршрутизаторами одинаков. Допустим, каждый маршрутизатор вычисляет LFA для определенного пути.
Как видно, единственный альтернативный путь при маршрутизации по IP приведет к образованию петли. Другими словами, в чистой IP сети LFA вычислить невозможно. Поэтому необходмо «сбросить» трафик чуть ближе к резервируемым префиксам, для чего прекрасно подойдет SR.
Исопользование SR в совокупности с PCE. Здесь и RSVP заменить можно, и полосу динамически отслеживать, и API организовать для сторонних инструментов. Разумеется, этот перечень скуден и не претендует на полный список всего, чего можно добиться с внедрением PCE в сеть. Но с транспортной точки зрения во главе всего станут гибкость управления сетью, возможность конфигурации intra-AS LSP (включая TE, L2VPN и пр.), простота конфигурации и развертывания сервисов. К тому же, PCE не требует редизайна сети и может работать поверх существующего forwarding plane.
Здесь меня снова понесло немного в сторону от SR. Однако связка SR+PCE выглядит очень многообещающей. И именно в этой связке segment routing раскрывает все свои преимущества.
4. Управление трафиком в больших сетях.
У Cisco есть нетривиальный подход к построению больших операторских сетей, который называется Unified MPLS. В иной терминологии тот же подход может называться Seamless MPLS. Сети с SR смогут стать отличной и более прозрачной альтернативой этому подходу.
Если вы представляете, какие усилия необходимо приложить для проектирования и конфигурации сети с использованием Unified MPLS с нуля, SR может вам приглянуться.
Взаимодействие LDP и SR
Я намеренно оставил этот раздел напоследок. Во-первых, далеко не всегда необходимо, чтобы SR и LDP взаимодействовали. Во-вторых, неплохо бы понимать, какие задачи могут быть решены с помощью SR до того, как переходить к вопросам взаимодействия с LDP.
Наиболее часто решаемые вопросы взаимодействия возникают при миграции с LDP на SR или при отсутствии поддержки SR на части устройств в сети. В IOS XR конфигурация SR безопасна. По умолачнию метки, полученные по LDP, имеют больший приоритет. Для того чтобы LDP ушел на второй план, необходимо сказать маршрутизатору segment-routing mpls sr-prefer в IGP процессе. При этом совершенно необязательно делать SR предпочитаемым на всех маршрутизаторах сразу. Эта команда локальна, и факт предпочтения SR никак не сообщается другим устройствам сети.
При наличии устройств, которые не поддерживают SR, необходимо сконфигурировать несколько устройств в качестве Mapping server. Я говорю несколько только из соображений отказоустойчивости — для функционирования будет достаточно одного устройства на границе SR/LDP сетей.
Mapping server получает метки по LDP, а затем анонсирует SID'ы от имени устройств, которые не умеют SR. При этом data plane не должен проходить через mapping server — это control plane устройство. Все маппинги, которые придумал сервер, анонсируются его клиентам через IGP. Каждое устройство должно быть сконфигурировано как клиент, чтобы получить маппинги для LDP сетей.
Сами маппинги задаются вручную. При этом в случае использования двух и более mapping servers ожидается, что маппинги на них будут сконфигурированы идентично. Конечно, сеть не сломается от неверно сконфигурированного маппинга, но в случае аварии сходимость может пострадать.
Имея mapping server можно защищать LSP, построенные протоколом LDP, в TI LFA. Другими словами, MPLS сервисы, метки для которых сгенерированы классическими протоколами, могут защищаться с использованием SR.
Существует множество сценариев взаимодействия LDP и SR, в их числе LDPoSR и SRoLDP. Чуть более подробное описание можно найти по одной из ссылок, приведенных ниже.
На этом мое короткое повествование о segment routing завершено. Хочу заметить, что материал в статье не рассматривает все нюансы SR и оставляет многое за кадром. Многое из того, что осталось за кадром, можно найти по ссылкам ниже.
Благодарю за внимание.
Ссылки на ресурсы IETF:
Очень полезный ресурс по SR: Cisco SR
Одна из сессий на Cisco Live: Introduction to Segment Routing
Читайте также: