Если вы не хотите споткнуться о те же подводные камни и потратить на создание компонента больше времени, чем ожидали - загляните в последний раздел статьи с финальным кодом. Привет, меня зовут Тёма Загоскин, я разрабатываю крутые штуки в Авиасейлс - сервисе по покупке дешевых авиабилетов. Год назад мы начали с нуля разрабатывать новый модуль, что позволило нам использовать модный молодежный SwiftUI. Казалось бы, идеальный инструмент для легкой верстки и красивых анимаций, поэтому очередная задача написать кастомный Segmented Control казалась тривиальной, тем более, что стандартный компонент кастомизируется буквально никак. Но, как оказалось, иногда на одну строчку кода могут уйти целые выходные. Первым делом - прототип без анимаций и украшательств. Спасибо SwiftUI за то, что на верстку компонентов, в целом готовых к работе, тратится от силы пара минут. Достаточно для MVP, но не очень хочется оставлять этот элемент в таком виде. Как сделать простенькую анимацию слайдинга? Один из вариантов - использовать GeometryReader, сохранять ширину и начальную координату каждого сегмента и менять оффсет вьюшки выбора по нажатию. Я же выбрал другую возможность - .matchedGeometryEffect(id: …, in: …), позволяющий синхронизировать вьюшки по id и namespace и делать с ними различные анимации (в нашем случае - перемещение) в одну строчку. Накидываем модификатор, добавляем анимацию: На двух элементах это выглядит хорошо, но когда их больше - плашка просто напросто перекрывает элементы, через которые проезжает: Это было ожидаемо, поэтому не отчаиваемся и движемся дальше. Какая у вас первая идея для перекрашивания текста в зависимости от плашки выбора? У меня - blendMode, который устанавливает стиль элемента в зависимости от его пересечения с другими вьюшками. К сожалению, этот вариант я отмел сразу, ведь мы не можем, например, дать цвет определенный цвет нужным компонентам сами. Тогда я начал смотреть в сторону черного оверлея с модификатором mask под выбранный контент. Появляется красивая анимация поэтапной смены цвета текста, но остается проблема с тем, что невыбранные опции не становятся черными при пересечении плашки выбора.  Видимо, от blendMode не уйти. Тогда надо залезть в шпаргалку и разобраться, как же все-таки можно достичь нужного варианта. Накидываем .blendMode(.difference) на контент, сверху оверлей с тем же контентом и .blendMode(.overlay), но у нас получается какая-то каша: Что ж, все-таки придется положить дополнительный пикер всех вариантов blendMode и перебирать. Так, попробовав все опции и сверившись со шпаргалкой, приходим к выводу, что надо положить между контентом и оверлеем еще один оверлей с контентом и .blendMode(.hue). Бинго, все красится как надо! А если еще и накинуть модификатор .transition(.offset()), задающий тип перехода, то пропадает портящий всю картину fade in: Но SwiftUI был бы не SwiftUI, если бы все было так просто. Проверяем это же в обратную сторону и... Промучившись какое-то время и перебрав всевозможные статьи про смену порядка модификаторов, я решил провести еще один эксперимент. По видео кажется, что проблема может быть в положении элементов по оси Z. Да, в коде я не использую ZStack’и, но попробовать стоит. Накидываем zIndex на сегмент в разных конфигурациях, понимаем, что выбранный элемент надо ставить ниже всех остальных, чтоб его бэкграунд точно был на самом нижнем уровне, и вуаля, элемент наконец готов улетать в продакшн. Готовый элемент, сделанный по дизайну - это безусловно хорошо, но иногда требуется возможность переиспользовать компоненты, а иногда даже немного кастомизировать. Я постарался сделать segmented control максимально гибким, поэтому если вы искали что-то на замену дефолтному - feel free to use CustomizableSegmentedControl. Подключается как через SPM, так и через CocoaPods. iOS Software Engineer