iPadOS 上的 SwiftUI 自定义鼠标指针
SwiftUI custom mouse pointer on 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?
提前致谢
如果您想使用 Apple 当前的 API 执行此操作,我认为您做不到。希望这样的功能会出现在未来的版本中。
但是,您仍然可以通过进行一些内省来启用此功能。
首先,警告:虽然常见的 UIKit 元素支持 iOS 上的 SwiftUI 视图,但不能保证在所有情况下都是如此。因此,此解决方案可能会在未来的某个时刻失效。
现在,一个可能的方法。
向您的应用添加内省包。过去,我使用 SwiftUI-Introspect(在我的视图中添加 UIDropInteraction
)。然后将 Introspect
模块导入到您的源文件中。
大多数内省包,例如这个包,都包含 View
扩展,可让您检查底层 UIKit 组件。根据您的观点,您将使用特定的修饰符。
例如,如果您想获取特定视图的底层视图控制器,您可以使用 .introspectViewController()
修饰符。您为它提供一个闭包,该闭包将被赋予视图控制器。您可以将您的交互添加到视图控制器的视图中。 (如果您有滚动视图,请使用 introspectScrollView
修饰符等)
示例,假设一个名为 PointerDelegate
的 class 符合 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()))
}
}
}
这有点骇人听闻,如前所述,将来可能会崩溃。但是,这是一种从您的 SwiftUI 应用程序中访问某些仅在 UIKit 中启用的功能的方法。
我们如何使用 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? 提前致谢
如果您想使用 Apple 当前的 API 执行此操作,我认为您做不到。希望这样的功能会出现在未来的版本中。
但是,您仍然可以通过进行一些内省来启用此功能。
首先,警告:虽然常见的 UIKit 元素支持 iOS 上的 SwiftUI 视图,但不能保证在所有情况下都是如此。因此,此解决方案可能会在未来的某个时刻失效。
现在,一个可能的方法。
向您的应用添加内省包。过去,我使用 SwiftUI-Introspect(在我的视图中添加 UIDropInteraction
)。然后将 Introspect
模块导入到您的源文件中。
大多数内省包,例如这个包,都包含 View
扩展,可让您检查底层 UIKit 组件。根据您的观点,您将使用特定的修饰符。
例如,如果您想获取特定视图的底层视图控制器,您可以使用 .introspectViewController()
修饰符。您为它提供一个闭包,该闭包将被赋予视图控制器。您可以将您的交互添加到视图控制器的视图中。 (如果您有滚动视图,请使用 introspectScrollView
修饰符等)
示例,假设一个名为 PointerDelegate
的 class 符合 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()))
}
}
}
这有点骇人听闻,如前所述,将来可能会崩溃。但是,这是一种从您的 SwiftUI 应用程序中访问某些仅在 UIKit 中启用的功能的方法。