feat: 初始化 iOS 远程控制端项目
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
|
||||
/// UIKit 触控捕获视图:将触摸转换为相对坐标(0.0~1.0)的远端输入指令。
|
||||
/// 与 Android 端 RemoteTouchView 行为一致:
|
||||
/// - 实时转发原始 MotionEvent(DOWN=0 / UP=1 / MOVE=2 / CANCEL=3),远端注入实现"跟手"
|
||||
/// - 手指抬起时若判定为滑动(时长 >= 200ms 或位移 >= 2%),额外发送一条 SWIPE 指令
|
||||
final class RemoteTouchView: UIView {
|
||||
|
||||
/// Android MotionEvent 动作常量
|
||||
enum MotionAction {
|
||||
static let down: Int32 = 0
|
||||
static let up: Int32 = 1
|
||||
static let move: Int32 = 2
|
||||
static let cancel: Int32 = 3
|
||||
}
|
||||
|
||||
var onMotionEvent: ((Int32, Double, Double) -> Void)?
|
||||
var onSwipe: ((Double, Double, Double, Double, Int64) -> Void)?
|
||||
|
||||
private var startX: Double = 0
|
||||
private var startY: Double = 0
|
||||
private var touchStartTime: TimeInterval = 0
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
isMultipleTouchEnabled = false
|
||||
backgroundColor = .clear
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
isMultipleTouchEnabled = false
|
||||
backgroundColor = .clear
|
||||
}
|
||||
|
||||
private func relativePoint(of touch: UITouch) -> (Double, Double) {
|
||||
let p = touch.location(in: self)
|
||||
let w = max(bounds.width, 1)
|
||||
let h = max(bounds.height, 1)
|
||||
let relX = min(max(Double(p.x / w), 0), 1)
|
||||
let relY = min(max(Double(p.y / h), 0), 1)
|
||||
return (relX, relY)
|
||||
}
|
||||
|
||||
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
guard let touch = touches.first else { return }
|
||||
let (x, y) = relativePoint(of: touch)
|
||||
startX = x
|
||||
startY = y
|
||||
touchStartTime = Date().timeIntervalSince1970
|
||||
onMotionEvent?(MotionAction.down, x, y)
|
||||
}
|
||||
|
||||
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
guard let touch = touches.first else { return }
|
||||
let (x, y) = relativePoint(of: touch)
|
||||
onMotionEvent?(MotionAction.move, x, y)
|
||||
}
|
||||
|
||||
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
guard let touch = touches.first else { return }
|
||||
let (x, y) = relativePoint(of: touch)
|
||||
onMotionEvent?(MotionAction.up, x, y)
|
||||
|
||||
let duration = Int64((Date().timeIntervalSince1970 - touchStartTime) * 1000)
|
||||
let dx = abs(x - startX)
|
||||
let dy = abs(y - startY)
|
||||
// 非轻点:补发 SWIPE 高层指令(与 Android 端一致)
|
||||
if !(duration < 200 && dx < 0.02 && dy < 0.02) {
|
||||
onSwipe?(startX, startY, x, y, duration)
|
||||
}
|
||||
}
|
||||
|
||||
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
guard let touch = touches.first else { return }
|
||||
let (x, y) = relativePoint(of: touch)
|
||||
onMotionEvent?(MotionAction.cancel, x, y)
|
||||
}
|
||||
}
|
||||
|
||||
/// SwiftUI 包装:把 UIKit 触控层嵌入 SwiftUI 视图树
|
||||
struct TouchOverlay: UIViewRepresentable {
|
||||
let onMotionEvent: (Int32, Double, Double) -> Void
|
||||
let onSwipe: (Double, Double, Double, Double, Int64) -> Void
|
||||
|
||||
func makeUIView(context: Context) -> RemoteTouchView {
|
||||
let view = RemoteTouchView()
|
||||
view.onMotionEvent = onMotionEvent
|
||||
view.onSwipe = onSwipe
|
||||
return view
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: RemoteTouchView, context: Context) {
|
||||
uiView.onMotionEvent = onMotionEvent
|
||||
uiView.onSwipe = onSwipe
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user