如果我们查阅the NSCursor
documentation,我们会找到关于"光标矩形"的讨论:
在Cocoa中,您可以根据鼠标在某个视图上的位置来更改当前显示的光标.您可以使用此技术来提供有关用户可以使用鼠标执行哪些操作的可视反馈.例如,每当鼠标移动到用作自定义大小调整手柄的视图部分上时,您可能会显示其中一个调整大小的光标.要进行此设置,您需要将一个光标对象与视图中的一个或多个光标矩形相关联.
让我们写一个ViewModifier
来设置一个光标矩形.
extension View {
func cursor(_ cursor: NSCursor) -> some View {
self.modifier(CursorModifier(cursor: cursor))
}
}
struct CursorModifier: ViewModifier {
let cursor: NSCursor
func body(content: Content) -> some View {
content
.background { Rep(cursor: cursor) }
}
}
修改器会将类型为Rep
的background
视图添加到修改后的视图中.但是Rep
是什么呢?它是一款NSViewRepresentable
,包装了一款定制的NSView
.NSView
覆盖resetCursorRects
以创建覆盖整个NSView
的光标矩形.
extension CursorModifier {
private struct Rep: NSViewRepresentable {
let cursor: NSCursor
func makeNSView(context: Context) -> NSViewType {
return NSViewType(cursor: cursor)
}
func updateNSView(_ nsView: NSViewType, context: Context) {
nsView.cursor = cursor
}
class NSViewType: NSView {
var cursor: NSCursor
init(cursor: NSCursor) {
self.cursor = cursor
super.init(frame: .zero)
}
required init?(coder: NSCoder) { fatalError() }
override func resetCursorRects() {
addCursorRect(bounds, cursor: cursor)
}
}
}
}
为了测试它,我将设置一个SwiftUI视图,其中包含Text
(不应影响光标)和TextField
(悬停时应显示the iBeam
cursor).
struct ContentView: View {
@State var text: String = ""
var body: some View {
VStack {
Spacer()
Text("Hello, world!")
TextField("Input:", text: $text)
Spacer()
}
.padding()
.cursor(.pointingHand)
}
}
结果:
请注意,我必须将Spacer
放在VStack
中,才能让VStack
填满窗口.否则,窗口可以比VStack
更高,并且VStack
之外的窗口部分不使用指点手.