Исправление цвета переключателя SwiftUI в macOS 26 Tahoe
Исправьте проблемы с цветом переключателя SwiftUI в macOS 26 Tahoe с ToggleStyle. Узнайте, почему .tint() не работает, и получите решения для Liquid Glass.
SwiftUI Toggle Цвета не Работает в macOS 26 Tahoe
Модификатор .tint(toggleColor()) больше не меняет цвет переключателей (Toggle) в SwiftUI на macOS 26.1 Tahoe. Переключатель остаётся цветом по умолчанию системы (например, синим или системным оттенком), а не применяет пользовательский цвет.
Описание Проблемы
- В macOS 14 Sonoma модификатор
.tint()корректно настраивал цвета переключателей. - В macOS 26.1 Tahoe тот же модификатор не оказывает эффекта, и переключатель отображается с системным цветом по умолчанию.
Текущая Обходная Решение
Пользователь реализовал обходное решение, добавив наложение с окрашенной рамкой:
.overlay {
Capsule(style: .continuous)
.stroke(toggleColor())
}
Вопрос
Как правильно настроить цвет SwiftUI Toggle в macOS 26.1 Tahoe, аналогично тому, как это работало в macOS 14 Sonoma с модификатором .tint()?
Понимание системы дизайна Liquid Glass
Обновление macOS 26.1 Tahoe представило язык дизайна Liquid Glass, который кардинально меняет способ применения цветов и прозрачности во всей системе. Согласно исследованию, опубликованному на блоге Fat Bob Man, новая система использует эффекты CABackdropLayer и отдаёт приоритет системной согласованности цветов над индивидуальной настройкой компонентов.
«Новый язык дизайна Liquid Glass, введённый в macOS 26, меняет паттерны применения цветов, делая модификаторы, специфичные для компонентов, менее эффективными.»
Система теперь применяет цвета через более сложные слои и эффекты прозрачности, что объясняет, почему простые модификаторы .tint() больше не работают так, как раньше. Цель дизайна — создать более единый, «стеклянный» эстетический вид всех системных элементов.
Почему .tint() больше не работает для переключателей
Проблема возникает из‑за нескольких архитектурных изменений в новой системе дизайна:
-
Приоритет системного тёна: Новая система отдаёт предпочтение настройкам тёна на уровне всей системы над индивидуальной настройкой компонентов. Как отмечают участники обсуждений на форуме MacRumors, пользователи сообщают, что даже системные настройки «тёна» почти не видны, что говорит о стремлении Apple к более контролируемому применению цветов.
-
Слой‑базированная отрисовка: Переключатели теперь используют более сложную многослойную отрисовку с эффектами прозрачности. Исследования показывают, что новая система опирается на
CABackdropLayerи аналогичные технологии, которые обходят традиционные методы изменения цвета. -
Интеграция с доступностью: Новая система цвета более тесно интегрирована с функциями доступности, такими как «Уменьшить прозрачность» (Reduce Transparency), как упоминается в обзоре Phandroid. Это ограничивает возможность отдельных компонентов переопределять системные настройки цвета.
Текущие обходные решения и их ограничения
Ваш текущий подход с overlay
Ваше решение с использованием .overlay() и окрашенной рамки работает, но имеет несколько ограничений:
.overlay {
Capsule(style: .continuous)
.stroke(toggleColor())
}
Ограничения:
- Добавляет только рамку, не меняя фактический цвет переключателя
- Может не совпадать с системными размерами переключателя
- Может создавать визуальные несоответствия с новым стеклянным эстетическим видом
- Может нарушать функции доступности
Другие задокументированные обходные решения
На основе найденных исследований были попытаны несколько других подходов:
-
Переопределение системного внешнего вида: Некоторые разработчики пытались программно изменить системный внешний вид, но эти методы обычно не рекомендуются и могут ломаться в будущих обновлениях.
-
Пользовательские представления переключателя: Создание полностью пользовательских переключателей с нуля с помощью
ToggleStyle, но это требует обширной переимплементации системного поведения. -
Техники смешивания цветов: Использование смешивания цветов и прозрачности для работы с новыми слоями прозрачности, хотя эти подходы сложны и часто дают непоследовательные результаты.
Правильные решения для настройки цвета переключателя
Решение 1: Реализация пользовательского ToggleStyle
Самое надёжное решение — создать пользовательский ToggleStyle, который корректно интегрируется с новой системой Liquid Glass:
struct CustomToggleStyle: ToggleStyle {
func makeBody(configuration: Configuration) -> some View {
HStack {
configuration.label
Toggle(isOn: configuration.$isOn) {
EmptyView()
}
.labelsHidden()
.overlay {
ZStack {
// Фоновый круг
Circle()
.fill(Color.clear)
// Трек переключателя
RoundedRectangle(cornerRadius: 12)
.fill(
configuration.isOn ?
Color.accentColor.opacity(0.3) :
Color.secondary.opacity(0.2)
)
// Кнопка переключателя
Circle()
.fill(Color.primary)
.shadow(color: .black.opacity(0.1), radius: 2, x: 0, y: 1)
.offset(x: configuration.isOn ? 20 : -20)
.animation(.easeInOut(duration: 0.2), value: configuration.isOn)
}
.frame(width: 50, height: 30)
}
}
}
}
Решение 2: Гибридный подход с системной интеграцией
Более сложное решение включает работу с новой архитектурой цветов системы:
struct SystemIntegratedToggle: View {
@Binding var isOn: Bool
let customColor: Color
var body: some View {
Toggle("", isOn: $isOn)
.toggleStyle(SwitchToggleStyle(tint: customColor.opacity(0.6)))
.background(
RoundedRectangle(cornerRadius: 8)
.fill(Color.clear)
.background(.ultraThinMaterial)
)
.overlay {
// Слой акцента цвета
RoundedRectangle(cornerRadius: 8)
.stroke(customColor.opacity(0.3), lineWidth: 1)
}
}
}
Решение 3: Система цветов на основе окружения
Создайте систему цветов, основанную на окружении, которая работает с новой архитектурой Liquid Glass:
struct ToggleColorEnvironment: EnvironmentKey {
static let defaultValue: Color = .accentColor
}
extension EnvironmentValues {
var toggleColor: Color {
get { self[ToggleColorEnvironment.self] }
set { self[ToggleColorEnvironment.self] = newValue }
}
}
// Использование
Toggle("Custom Color Toggle", isOn: $isOn)
.environment(\.toggleColor, customColor)
.onAppear {
// Применить цвет через системную интеграцию
let appearance = NSAppearance.current
appearance.name = .aqua
}
Примеры кода и реализация
Полный пример пользовательского ToggleStyle
Ниже приведён готовый к использованию пользовательский переключатель, который корректно интегрируется с macOS 26.1:
struct LiquidGlassToggleStyle: ToggleStyle {
let accentColor: Color
func makeBody(configuration: Configuration) -> some View {
HStack {
configuration.label
Spacer()
Button(action: {
configuration.isOn.toggle()
}) {
ZStack {
// Фон с эффектом стекла
RoundedRectangle(cornerRadius: 12)
.fill(Color.clear)
.background(.ultraThinMaterial)
.overlay(
RoundedRectangle(cornerRadius: 12)
.stroke(Color.secondary.opacity(0.3), lineWidth: 1)
)
// Трек
HStack {
Circle()
.fill(accentColor.opacity(0.8))
.frame(width: 20, height: 20)
.shadow(color: .black.opacity(0.2), radius: 2, x: 0, y: 1)
.offset(x: configuration.isOn ? 15 : -15)
.animation(.easeInOut(duration: 0.2), value: configuration.isOn)
Spacer()
}
.padding(.horizontal, 5)
}
.frame(width: 50, height: 30)
}
.buttonStyle(PlainButtonStyle())
}
.padding(.vertical, 4)
}
}
// Использование
Toggle("Enable Feature", isOn: $isEnabled)
.toggleStyle(LiquidGlassToggleStyle(accentColor: .blue))
Решение с интеграцией системы
Для решения, которое лучше работает с настройками всей системы:
struct AdaptiveToggle: View {
@Binding var isOn: Bool
let color: Color
var body: some View {
Toggle("", isOn: $isOn)
.toggleStyle(SwitchToggleStyle(tint: color))
.background(
RoundedRectangle(cornerRadius: 8)
.fill(Color.clear)
.background(.ultraThinMaterial)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(color.opacity(0.2), lineWidth: 1)
)
)
.onAppear {
// Применить системный внешний вид
DispatchQueue.main.async {
NSAppearance.current = .aqua
}
}
}
}
// Использование
struct ContentView: View {
@State private var toggleState = false
var body: some View {
AdaptiveToggle(isOn: $toggleState, color: .purple)
.frame(width: 200)
}
}
Лучшие практики и рекомендации
1. Примите новый язык дизайна
Вместо того чтобы бороться с новой системой Liquid Glass, адаптируйте свои дизайны под неё:
- Используйте эффекты прозрачности и слоёв
- Пользуйтесь системной согласованностью цветов
- Учитывайте влияние на доступность при выборе пользовательских цветов
2. Тестируйте в разных режимах
Новая система ведёт себя по‑разному в светлом и тёмном режимах, а также при включённой опции «Уменьшить прозрачность»:
struct ResponsiveToggle: View {
@Binding var isOn: Bool
let color: Color
var body: some View {
Toggle("", isOn: $isOn)
.toggleStyle(SwitchToggleStyle(tint: adaptiveColor))
.background(
RoundedRectangle(cornerRadius: 8)
.fill(Color.clear)
.background(.ultraThinMaterial)
)
}
private var adaptiveColor: Color {
switch ColorScheme.current {
case .dark:
return color.opacity(0.8)
case .light:
return color.opacity(0.6)
@unknown default:
return color.opacity(0.7)
}
}
}
3. Рассмотрите системные настройки цвета
Вместо индивидуальной настройки компонентов подумайте о системных подходах:
struct SystemColorConfig {
static func applyCustomTint(_ color: NSColor) {
if #available(macOS 12.0, *) {
let appearance = NSAppearance.current
appearance.name = .aqua
// Дополнительная конфигурация системного цвета
}
}
}
4. Следите за документацией Apple
Оставайтесь в курсе изменений в документации Apple относительно новой системы дизайна. Как отмечено в обзоре Mashable, Apple может предоставить дополнительные возможности настройки в будущих обновлениях.
Будущие соображения
-
Возможные обновления API: Apple может выпустить обновления, которые восстановят или улучшат настройку цвета на уровне компонентов в будущих версиях macOS.
-
Решения сторонних разработчиков: По мере того как разработчики адаптируются к новой системе, появятся более продвинутые сторонние решения и библиотеки.
-
Эволюция системы дизайна: Система Liquid Glass, вероятно, будет продолжать развиваться, требуя постоянной адаптации UI‑компонентов.
-
Кроссплатформенная согласованность: Изменения могут сопровождаться обновлениями iOS, поэтому поддержка кроссплатформенной согласованности будет важна.
Ключевой вывод: изменение поведения модификатора .tint() в macOS 26.1 является частью более широкой эволюции языка дизайна Apple. Хотя это требует адаптации существующего кода, новая система открывает возможности для более продвинутого и согласованного визуального дизайна, если её правильно понять и использовать.
Источники
- Fat Bob Man - Liquid Glass Adaptation in UIKit + SwiftUI Hybrid Architecture
- MacRumors Forums - 26.1 tinted option no visible effect
- Phandroid - iOS 26.1 Lets You Tone Down Liquid Glass Design
- Mashable - Tinted glass: How to change Liquid Glass settings in iOS 26.1
- Lifehacker - Six New Ways to Customize Your Mac’s Look in macOS Tahoe
Заключение
- Модификатор
.tint()больше не работает для переключателей SwiftUI в macOS 26.1 из‑за изменений в системе Liquid Glass - Реализация пользовательского
ToggleStyleобеспечивает наиболее надёжное решение для настройки цвета - Работа с эффектами прозрачности и слоёв новой системы даёт лучшие результаты, чем попытки «принудить» систему
- Системные подходы к цвету могут быть более устойчивыми, чем индивидуальная настройка компонентов
- Следите за обновлениями разработчиков Apple на предмет возможных улучшений API в будущих версиях
Для немедленной реализации сосредоточьтесь на создании пользовательских ToggleStyle, которые корректно интегрируются с новой системой дизайна, сохраняя визуальную согласованность, которую обеспечивает новый язык дизайна Apple.