Стиль вставки для представления

Вопрос или проблема

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

Segmented Picker

Мне удалось создать аналогичное управление с помощью HStack и нескольких кнопок, в основном создав тот же вид и ощущения:

Custom Picker

Тем не менее, ближайшее, что мне удалось сделать к инсетному фону, – это использовать фон .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())

Объяснение изменений

  1. Фон и цвет кнопки: Используйте .thinMaterial как фон для выделенной кнопки. Это создаст эффект подложки, схожей с инсет стилем. Для невыделенной кнопки установите .clear, что позволит сохранить легкость интерфейса.

  2. Отступы и тень: Добавление отступов улучшает восприятие кнопок. Использование тени сделает кнопку более "объемной", что выделяет её на фоне остальных.

  3. Эффект масштабирования: Легкое увеличение (
    scaleEffect) выбранной кнопки придаст вам 3D-эффект. Это визуально подчеркивает активный выбор пользователя.

  4. Анимация: Используйте animation для создания плавного перехода между состояниями кнопок.

Заключение

Создание кастомного компонента в SwiftUI требует творчества и гибкости. Используя вышеприведённые решения, вы сможете достичь желаемого инсет стиля и обеспечить требуемую функциональность через уникальные подсказки для каждой кнопки. Это улучшит пользовательский опыт, а также добавит профессионального вида вашему интерфейсу.

Оцените материал
Добавить комментарий

Капча загружается...