Вопрос или проблема
В настоящее время мы используем Picker с сегментированным стилем pickerStyle, чтобы позволить пользователям менять инструменты. Однако нам действительно нужно иметь разные подсказки для каждой кнопки, чего, похоже, сейчас нет.
Мне удалось создать аналогичное управление с помощью HStack и нескольких кнопок, в основном создав тот же вид и ощущения:
Тем не менее, ближайшее, что мне удалось сделать к инсетному фону, – это использовать фон .thickMaterial
, который создает некоторый контраст, но не выглядит так хорошо, как инсетный фон родного элемента Picker. Есть ли способ имитировать тот же инсетный стиль?
Также было бы неплохо получить тот же 3D-вид на выбранной кнопке, если это возможно.
Вот текущий код:
HStack {
ForEach(ToolType.allCases, id: \.self) { toolType in
if toolType == toolManager.tool {
Button {
} label: {
Image(systemName: toolType.iconName())
.tint(.white)
}
.frame(width: 44, height: 36)
.background(.thinMaterial)
.mask(Capsule())
.tag(toolType)
.help(toolType.name())
} else {
Button {
toolManager.tool = toolType
} label: {
Image(systemName: toolType.iconName())
.frame(width: 44, height: 36)
.foregroundStyle(.gray)
}
.tag(toolType)
.background(.clear)
.mask(Capsule())
.buttonStyle(.plain)
.help(toolType.name())
}
}
}
.frame(width: 5 * 52, height: 44)
.background(.thickMaterial)
.mask(Capsule())
Вот код с использованием родного Picker:
Picker("Инструменты", selection: $toolManager.tool) {
ForEach(ToolType.allCases, id: \.self) { toolType in
Image(systemName: toolType.iconName())
.tag(toolType)
}
}
.pickerStyle(.segmented)
.frame(width: CGFloat(50 * ToolType.allCases.count)) //Раздвинуть кнопки немного.
.help("Инструменты")
Ответ или решение
Инструменты выбора с инсет стилем для пользовательского интерфейса в SwiftUI
При разработке пользовательских интерфейсов в SwiftUI часто требуется отойти от стандартных компонентов, чтобы удовлетворить специфические требования дизайна. Одной из таких задач является создание кастомного компонента для выбора инструментов с использованием стиля вставки (inset style), который не поддерживается стандартным Picker
с сегментированным стилем. В этом ответе мы рассмотрим, как можно создать внешний вид, схожий с инсет стилем, при этом обеспечив возможность отображения различных подсказок для каждой кнопки.
Проблема
Ваша текущая реализация Picker
не предоставляет функционала для отображения уникальных подсказок для каждой кнопки, что затрудняет взаимодействие пользователя с интерфейсом. Используйте вместо этого кастомный HStack
с кнопками, чтобы добиться желаемой функциональности и стиля.
Решение
В вашем коде уже начинается создание пользовательского интерфейса с использованием HStack
. Тем не менее, для достижения желаемого инсет стиля и 3D-эффекта выделяемой кнопки, вам нужно внести некоторые изменения. Во-первых, следует изменить фон и шрифты для создания более четкого визуального эффекта.
Оптимизированный код
Вот переработанный вариант вашего кода с учётом указанных принципов:
HStack {
ForEach(ToolType.allCases, id: \.self) { toolType in
Button {
toolManager.tool = toolType
} label: {
Image(systemName: toolType.iconName())
.frame(width: 44, height: 36)
.padding() // Добавьте отступы для улучшенного внешнего вида
.background(toolManager.tool == toolType ? .thinMaterial : .clear)
.foregroundColor(toolManager.tool == toolType ? .white : .gray)
.clipShape(Capsule())
.shadow(color: toolManager.tool == toolType ? Color.black.opacity(0.2) : .clear, radius: 4, x: 2, y: 2) // Добавление тени
.scaleEffect(toolManager.tool == toolType ? 1.05 : 1.0) // Эффект увеличения для выделенной кнопки
.animation(.easeInOut, value: toolManager.tool) // Плавная анимация при изменении
}
.help(toolType.name())
}
}
.frame(width: CGFloat(52 * ToolType.allCases.count), height: 44)
.background(.thinMaterial) // Используйте менее агрессивный фон
.mask(Capsule())
Объяснение изменений
-
Фон и цвет кнопки: Используйте
.thinMaterial
как фон для выделенной кнопки. Это создаст эффект подложки, схожей с инсет стилем. Для невыделенной кнопки установите.clear
, что позволит сохранить легкость интерфейса. -
Отступы и тень: Добавление отступов улучшает восприятие кнопок. Использование тени сделает кнопку более "объемной", что выделяет её на фоне остальных.
-
Эффект масштабирования: Легкое увеличение (
scaleEffect
) выбранной кнопки придаст вам 3D-эффект. Это визуально подчеркивает активный выбор пользователя. -
Анимация: Используйте
animation
для создания плавного перехода между состояниями кнопок.
Заключение
Создание кастомного компонента в SwiftUI требует творчества и гибкости. Используя вышеприведённые решения, вы сможете достичь желаемого инсет стиля и обеспечить требуемую функциональность через уникальные подсказки для каждой кнопки. Это улучшит пользовательский опыт, а также добавит профессионального вида вашему интерфейсу.