You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在iPadOS中使用SwiftUI为视图实现自定义鼠标指针效果

实现方案

要求运行环境为 iPadOS 13.4 及以上版本,通过桥接 UIKit 指针交互 API 实现和示例完全一致的自定义效果:

第一步:封装交互逻辑

import SwiftUI
import UIKit

struct PointerInteractionView: UIViewRepresentable {
    var useStraightLineStitch: Bool
    var gridHeight: CGFloat
    
    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }
    
    func makeUIView(context: Context) -> UIView {
        let view = UIView(frame: .zero)
        view.backgroundColor = .clear
        let interaction = UIPointerInteraction(delegate: context.coordinator)
        view.addInteraction(interaction)
        return view
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {
        context.coordinator.parent = self
    }
    
    class Coordinator: NSObject, UIPointerInteractionDelegate {
        var parent: PointerInteractionView
        
        init(parent: PointerInteractionView) {
            self.parent = parent
        }
        
        func pointerInteraction(_ interaction: UIPointerInteraction, regionFor request: UIPointerRegionRequest, defaultRegion: UIPointerRegion) -> UIPointerRegion? {
            if parent.useStraightLineStitch {
                let regionNumber = floor(request.location.y / parent.gridHeight)
                return UIPointerRegion(rect: CGRect(
                    x: 0,
                    y: regionNumber * parent.gridHeight,
                    width: interaction.view?.bounds.width ?? 0,
                    height: parent.gridHeight
                ))
            } else {
                return defaultRegion
            }
        }
        
        func pointerInteraction(_ interaction: UIPointerInteraction, styleFor region: UIPointerRegion) -> UIPointerStyle? {
            let crosshair = UIPointerShape.path(crosshairBezierPath())
            if parent.useStraightLineStitch {
                return UIPointerStyle(shape: crosshair, constrainedAxes: [.vertical])
            } else {
                return UIPointerStyle(shape: crosshair)
            }
        }
        
        private 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
        }
    }
}

extension View {
    func customPointer(useStraightLineStitch: Bool, gridHeight: CGFloat) -> some View {
        self.background(
            PointerInteractionView(useStraightLineStitch: useStraightLineStitch, gridHeight: gridHeight)
                .allowsHitTesting(false)
        )
    }
}

第二步:调用示例

直接给需要添加自定义指针的 SwiftUI 视图挂载上方封装好的 modifier 即可:

struct QuiltView: View {
    // 可动态修改的业务参数
    @State private var useStraightLineStitch = true
    @State private var gridHeight: CGFloat = 44
    
    var body: some View {
        // 这里替换为你原本的视图内容
        Rectangle()
            .fill(.gray.opacity(0.2))
            .frame(width: 300, height: 600)
            // 应用自定义指针效果
            .customPointer(useStraightLineStitch: useStraightLineStitch, gridHeight: gridHeight)
    }
}

以上实现完全对齐原 UIKit 示例的指针样式、区域计算逻辑,支持参数动态更新。

内容的提问来源于stack exchange,提问作者Tiago Mendes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.10 11:36:00