#swift #ipad #swiftui #ipados
Вопрос:
Как мы можем использовать пользовательский указатель мыши для просмотра с помощью SwiftUI iPadOS?
У Apple есть пример того, как это сделать в этом коде, но он предназначен для UIKit: https://developer.apple.com/documentation/uikit/pointer_interactions/enhancing_your_ipad_app_with_pointer_interactions
class QuiltView: UIView, UIPointerInteractionDelegate {
...
func sharedInit() {
...
// Add a pointer interaction for the "editor" area Quilt view.
self.addInteraction(UIPointerInteraction(delegate: self))
}
// Supply custom regions that correspond to grid lines when "useStraightLineStitch" is enabled.
func pointerInteraction(_ interaction: UIPointerInteraction,
regionFor request: UIPointerRegionRequest,
defaultRegion: UIPointerRegion) -> UIPointerRegion? {
if useStraightLineStitch {
let regionNumber = floor(request.location.y / gridHeight)
return UIPointerRegion(rect: CGRect(x: 0, y: regionNumber * gridHeight, width: self.bounds.size.width, height: gridHeight))
} else {
return defaultRegion
}
}
// Supply pointer style with custom crosshair shape.
func pointerInteraction(_ interaction: UIPointerInteraction, styleFor region: UIPointerRegion) -> UIPointerStyle? {
let crosshair = UIPointerShape.path(crosshairBezierPath())
if useStraightLineStitch {
return UIPointerStyle(shape: crosshair, constrainedAxes: [.vertical])
} else {
return UIPointerStyle(shape: crosshair)
}
}
func crosshairBezierPath() -> UIBezierPath {
let crosshairPath = UIBezierPath()
crosshairPath.move(to: CGPoint(x: -1.5, y: 1.5))
crosshairPath.addLine(to: CGPoint(x: -1.5, y: 10))
crosshairPath.addArc(withCenter: CGPoint(x: 0, y: 10),
radius: 1.5,
startAngle: CGFloat.pi,
endAngle: 0,
clockwise: false)
crosshairPath.addLine(to: CGPoint(x: 1.5, y: 1.5))
crosshairPath.addLine(to: CGPoint(x: 10, y: 1.5))
crosshairPath.addArc(withCenter: CGPoint(x: 10, y: 0),
radius: 1.5,
startAngle: CGFloat.pi / 2.0,
endAngle: CGFloat.pi * 1.5,
clockwise: false)
crosshairPath.addLine(to: CGPoint(x: 1.5, y: -1.5))
crosshairPath.addLine(to: CGPoint(x: 1.5, y: -10))
crosshairPath.addArc(withCenter: CGPoint(x: 0, y: -10),
radius: 1.5,
startAngle: 0,
endAngle: CGFloat.pi,
clockwise: false)
crosshairPath.addLine(to: CGPoint(x: -1.5, y: -1.5))
crosshairPath.addLine(to: CGPoint(x: -10, y: -1.5))
crosshairPath.addArc(withCenter: CGPoint(x: -10, y: 0),
radius: 1.5,
startAngle: CGFloat.pi * 1.5,
endAngle: CGFloat.pi / 2.0,
clockwise: false)
crosshairPath.close()
return crosshairPath
}
...
}
Что я ищу, так это добиться того же, но с использованием SwiftUI? заранее спасибо
Ответ №1:
Если вы хотите сделать это с помощью текущих API Apple, я не верю, что вы можете это сделать. Надеюсь, такая функция появится в будущем выпуске.
Тем не менее, вы все равно можете включить эту функцию, проведя некоторый самоанализ.
Во-первых, предупреждение: хотя общие элементы UIKit поддерживают представления SwiftUI в iOS, это не гарантируется во всех случаях. Поэтому это решение может сломаться в какой-то момент в будущем.
Теперь перейдем к возможному подходу.
Добавьте пакет самоанализа в свое приложение. В прошлом я использовал SwiftUI-Самоанализ (чтобы добавить a UIDropInteraction
к своим взглядам). Затем импортируйте Introspect
модуль в свой исходный файл.
Большинство пакетов самоанализа, таких как этот, включают View
расширения, позволяющие изучить базовые компоненты UIKit. В зависимости от вашего представления вы будете использовать определенный модификатор.
Например, если вы хотите получить базовый контроллер представления для определенного представления, вам следует использовать .introspectViewController()
модификатор. Вы предоставляете ему закрытие, которое будет предоставлено контроллеру представления. Вы можете добавить свое взаимодействие в представление контроллера представления. (Если у вас есть вид прокрутки, используйте introspectScrollView
модификатор и т. Д.)
Пример, предполагая PointerDelegate
, что имя класса соответствует UIPointerInteractionDelegate
:
import SwiftUI
import Introspect
struct YourView: View {
var body: some View {
// Your view hierarchy
// For instance
List { ... }
.introspectViewController { viewController in
viewController.view.addInteraction(UIPointerInteraction(delegate: PointerDelegate()))
}
}
}
Это немного похоже на взлом, и, как предупреждалось ранее, в будущем может произойти сбой. Однако это способ получить доступ к некоторым функциям, которые включены в UIKit только в ваших приложениях SwiftUI.
Комментарии:
1. Эй, Джош, спасибо за ваше предложение, ваше предложение действительно интересно, но оно не сработало для меня с помощью UIPointerInteraction. Возможно, возможный способ-использовать функциональность, представленную в UIView, но мне все равно нужно немного узнать об этом.
2. @TiagoMendes Опробовал это сегодня утром, пара комментариев: (1) Вам нужно сохранить своего делегата. Сделать его одноэлементным и передать его в
UIPointerInteraction(delegate:)
вызов должно сработать. (2) Если вы не добавляете это к чему-то конкретному в UIKit, например, к UITextField или UITableView, это трудно самоанализировать. Если вы просто ищете UIView, вы можете легко получить неправильный вид или вид без ширины/высоты.3. Я отмечаю ваш ответ как правильный, ваше решение сработало /- . Всякий раз, когда я щелкаю, курсор исчезает, а круг возвращается, и в некоторых элементах он показывает только круг. Но лучше иметь это, чем ничего не иметь. Большое вам спасибо за ваш ответ время, и давайте надеяться, что команда SwiftUI окажет поддержку в этом 😀
4. Не за что! Я рад, что это смогло вам помочь. Я тоже надеюсь, что большая часть этой функциональности изначально присуща SwiftUI.