Какое-то время у нас был только модификатор onHover(perform:) в SwiftUI, который вызывается, когда пользователь перемещает указатель над рамкой view (представление, вью, вьюшка) или от неё. Раньше не было официального способа непрерывного отслеживания местоположения указателя. Это изменилось с введением onContinuousHover(coordinateSpace:perform:) в macOS 13 и iPadOS 16.

Новый модификатор позволяет нам читать текущую HoverPhase и сообщает точное местоположение указателя, когда он находится в пределах границ view. Давайте посмотрим на это в действии.

Чтение фазы наведения и местоположения указателя

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

struct ContentView: View {
    @State private var hoverLocation: CGPoint = .zero
    @State private var isHovering = false
    
    var body: some View {
        RoundedRectangle(cornerRadius: 20, style: .continuous)
            .fill(.indigo)
            .frame(width: 400, height: 300)
            .onContinuousHover { phase in
                switch phase {
                case .active(let location):
                    hoverLocation = location
                    isHovering = true
                case .ended:
                    isHovering = false
                }
            }
    }
}

Чтобы проверить, работает ли наш код должным образом, мы поместим view Text с координатами указателя в overlay. Текст будет отображаться только тогда, когда пользователь наводит курсор на прямоугольник.

struct ContentView: View {
    @State private var hoverLocation: CGPoint = .zero
    @State private var isHovering = false
    
    var body: some View {
        RoundedRectangle(cornerRadius: 20, style: .continuous)
            .fill(.indigo)
            .frame(width: 400, height: 300)
            .onContinuousHover { phase in
                switch phase {
                case .active(let location):
                    hoverLocation = location
                    isHovering = true
                case .ended:
                    isHovering = false
                }
            }
            .overlay {
                if isHovering {
                    Text("x: \(hoverLocation.x), y: \(hoverLocation.y)")
                        .foregroundColor(.white)
                        .font(.title)
                }
            }
    }
}

Мы увидим, что текст сообщает координаты и указателя в локальном координатном пространстве view RoundedRectangle.

local (локальное) координатное пространство используется по умолчанию для onContinuousHover(perform:). При необходимости мы можем указать global (глобальное) или named (именованное) пространство.

Добавляем круг в месте указателя

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

struct ContentView: View {
    @State private var hoverLocation: CGPoint = .zero
    @State private var isHovering = false
    
    var body: some View {
        RoundedRectangle(cornerRadius: 20, style: .continuous)
            .fill(.indigo)
            .frame(width: 400, height: 300)
            .onContinuousHover { phase in
                switch phase {
                case .active(let location):
                    hoverLocation = location
                    isHovering = true
                case .ended:
                    isHovering = false
                }
            }
            .overlay {
                if isHovering {
                    Circle()
                        .fill(.white)
                        .opacity(0.5)
                        .frame(width: 30, height: 30)
                        .position(x: hoverLocation.x, y: hoverLocation.y)
                }
            }
    }
}

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

Связанные посты

· Adjust the direction of focus-based navigation in SwiftUI

· Programmatically open a new window in SwiftUI on macOS

· Detect focused window on macOS

· Get tap location in SwiftUI

Если вам нравится наш блог и вы хотите поддержать нас, вы можете спонсировать нас на GitHub.

Чтобы получать новости о блоге и советы по разработке, следите за нами в Твиттере.

Комментарии (0)