iPadOS 上的 SwiftUI 自定义鼠标指针

SwiftUI custom mouse pointer on iPadOS

我们如何使用 SwiftUI + iPadOS 在一个视图中使用自定义鼠标指针?

A​​pple 在这段代码中有一个如何做到这一点的示例,但它是针对 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 中启用的功能的方法。