Как отключить кольцо фокусировки (или подсветку) вокруг кнопки в SwiftUI на MacOS?

Мое приложение включает в себя две кнопки, и, желая быть хорошим пользователем платформы, я бы хотел, чтобы пользователь мог перемещаться по ним с помощью клавиатуры, когда у них включен System Settings > Keyboard > Keyboard navigation.

Однако это создает действительно ужасную подсветку вокруг моих кнопок, от которой я не могу избавиться.

В идеале я бы хотел настроить стиль своей кнопки, когда кнопка находится в фокусе (например, изменить фон или сделать текст жирным).

См. изображение ниже, где левая кнопка находится в фокусе и окружена уродливым оранжевым кольцом, частично скрывающим тень:

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
493
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Цвет выделения фокуса зависит от цвета акцента. Поэтому, если вы хотите изменить его на что-то более нейтральное, вы можете изменить цвет акцента.

Для большего контроля над укладкой вы можете применить свои ButtonStyle:

  • Если вы хотите оформить кнопку по-другому, когда она находится в фокусе, вы можете определить это с помощью переменной FocusState, а затем передать флаг стилю.
  • Границу фокуса можно отключить, применив .focusEffectDisabled().

Использование переменной FocusState также позволяет вам программно установить фокус на определенной кнопке, если вы этого захотите. Например, это может быть полезно для установки фокуса на кнопке ОК в диалоговом окне.

struct MyButtonStyle: ButtonStyle {
    let isFocused: Bool
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .padding()
            .frame(minWidth: 100)
            .foregroundStyle(.black)
            .fontWeight(isFocused ? .bold : .regular)
            .border(.black)
            .background(
                Group {
                    isFocused ? Color.yellow : Color.white
                }
                .shadow(color: .black, radius: 4, x: 2, y: 2)
            )
            .animation(.easeInOut, value: isFocused)
    }
}

struct ContentView: View {

    enum ButtonPurpose {
        case start
        case reset
    }

    @FocusState private var isFocused: ButtonPurpose?

    var body: some View {
        HStack(spacing: 20) {
            Button("Start") {}
                .focused($isFocused, equals: .start)
                .buttonStyle(MyButtonStyle(isFocused: isFocused == .start))
                .focusEffectDisabled()
            Button("Reset") {}
                .focused($isFocused, equals: .reset)
                .buttonStyle(MyButtonStyle(isFocused: isFocused == .reset))
        }
    }
}

Эффект фокуса отключен только на первой кнопке, поэтому его все еще можно увидеть на второй (с синим цветом акцента по умолчанию):

Animation

Ответ принят как подходящий

Вы можете использовать FocusState, чтобы отслеживать, какая кнопка в данный момент выбрана с помощью клавиатуры. Используя это, вы можете написать собственный ButtonStyle, который создает собственный эффект фокусировки, когда кнопка находится в фокусе. Вы можете отключить эффект фокусировки по умолчанию (синий контур), используя .focusEffectDisabled().

Передать состояние фокуса ButtonStyle немного сложно. Значение isFocusedсреды здесь как-то не работает. Вы можете изменить каждую кнопку индивидуально с помощью модификатора .buttonStyle с разными параметрами, как в ответе Бензи Низа, но я бы предпочел использовать собственное значение среды.

Например, вот стиль кнопки, который увеличивает кнопку, когда она находится в фокусе.

struct MyButtonStyle: ButtonStyle {
    @Environment(\.customFocus) var focus
    
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .scaleEffect(focus ? 1.5 : 1)
    }
}

struct CustomFocusKey: EnvironmentKey {
    static let defaultValue = false
}

extension EnvironmentValues {
    var customFocus: Bool {
        get { self[CustomFocusKey.self] }
        set { self[CustomFocusKey.self] = newValue }
    }
}

Вы можете использовать ViewModifier для передачи состояния фокуса:

struct CustomFocusModifier: ViewModifier {
    @FocusState var focus: Bool
    
    func body(content: Content) -> some View {
        content
            .focused($focus)
            .environment(\.customFocus, focus)
    }
}

extension View {
    func customFocus() -> some View {
        modifier(CustomFocusModifier())
    }
}

Пример использования:

HStack {
    Button("Foo") { ... }
        .customFocus()
    Button("Bar") { ... }
        .customFocus()
}
.buttonStyle(MyButtonStyle())
.focusEffectDisabled()

Другие вопросы по теме