Какое-то время у нас был только модификатор 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)
}
}
}
}
Мы увидим, что текст сообщает координаты x и y указателя в локальном координатном пространстве 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)
}
}
}
}
Обратите внимание: поскольку мы помещаем круг в наложение прямоугольника со скругленными углами, мы можем просто использовать координаты наведения, данные нам в локальном пространстве координат прямоугольника. В других случаях может потребоваться использовать глобальное координатное пространство или указать именованное.