added ios module
This commit is contained in:
106
ios/OralTrainer/Player/PlayerSurfaceView.swift
Normal file
106
ios/OralTrainer/Player/PlayerSurfaceView.swift
Normal file
@@ -0,0 +1,106 @@
|
||||
import AVFoundation
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
/// 与安卓端 OralTrainerPlayerView 对齐的播放区:
|
||||
/// - 单击:播放 / 暂停
|
||||
/// - 左划 / 右划:上一句 / 下一句(无句边界时回退为快退 / 快进)
|
||||
/// - 长按:按触摸点水平位置变速(左慢右快),松手恢复原速
|
||||
struct PlayerSurfaceView: UIViewRepresentable {
|
||||
let controller: PlayerController
|
||||
|
||||
func makeUIView(context: Context) -> VideoSurfaceView {
|
||||
let view = VideoSurfaceView()
|
||||
view.playerLayer.player = controller.player
|
||||
view.controller = controller
|
||||
return view
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: VideoSurfaceView, context: Context) {
|
||||
uiView.playerLayer.player = controller.player
|
||||
}
|
||||
}
|
||||
|
||||
final class VideoSurfaceView: UIView {
|
||||
weak var controller: PlayerController?
|
||||
|
||||
override class var layerClass: AnyClass {
|
||||
AVPlayerLayer.self
|
||||
}
|
||||
|
||||
var playerLayer: AVPlayerLayer {
|
||||
layer as! AVPlayerLayer
|
||||
}
|
||||
|
||||
private let minSwipeDistance: CGFloat = 48
|
||||
private let minSwipeVelocity: CGFloat = 160
|
||||
private let longPressTimeout: TimeInterval = 0.5
|
||||
|
||||
private var tapRecognizer: UITapGestureRecognizer!
|
||||
private var panRecognizer: UIPanGestureRecognizer!
|
||||
private var longPressRecognizer: UILongPressGestureRecognizer!
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
backgroundColor = .black
|
||||
playerLayer.videoGravity = .resizeAspect
|
||||
|
||||
tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
|
||||
panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
|
||||
panRecognizer.minimumNumberOfTouches = 1
|
||||
panRecognizer.maximumNumberOfTouches = 1
|
||||
longPressRecognizer = UILongPressGestureRecognizer(
|
||||
target: self,
|
||||
action: #selector(handleLongPress)
|
||||
)
|
||||
longPressRecognizer.minimumPressDuration = longPressTimeout
|
||||
|
||||
tapRecognizer.require(toFail: panRecognizer)
|
||||
tapRecognizer.require(toFail: longPressRecognizer)
|
||||
panRecognizer.require(toFail: longPressRecognizer)
|
||||
|
||||
addGestureRecognizer(tapRecognizer)
|
||||
addGestureRecognizer(panRecognizer)
|
||||
addGestureRecognizer(longPressRecognizer)
|
||||
isUserInteractionEnabled = true
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
@objc private func handleTap() {
|
||||
controller?.handleGesture(.singleTap)
|
||||
}
|
||||
|
||||
@objc private func handlePan(_ recognizer: UIPanGestureRecognizer) {
|
||||
guard recognizer.state == .ended || recognizer.state == .cancelled else {
|
||||
return
|
||||
}
|
||||
let translation = recognizer.translation(in: self)
|
||||
let velocity = recognizer.velocity(in: self)
|
||||
let dx = translation.x
|
||||
let dy = translation.y
|
||||
guard abs(dx) >= abs(dy),
|
||||
abs(dx) >= minSwipeDistance,
|
||||
abs(velocity.x) >= minSwipeVelocity else {
|
||||
return
|
||||
}
|
||||
controller?.handleGesture(dx > 0 ? .swipeRight : .swipeLeft)
|
||||
}
|
||||
|
||||
@objc private func handleLongPress(_ recognizer: UILongPressGestureRecognizer) {
|
||||
let location = recognizer.location(in: self)
|
||||
switch recognizer.state {
|
||||
case .began:
|
||||
controller?.beginLongPressSpeed(atX: location.x, width: bounds.width)
|
||||
case .changed:
|
||||
controller?.updateLongPressSpeed(atX: location.x, width: bounds.width)
|
||||
case .ended, .cancelled:
|
||||
controller?.endLongPressSpeed()
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user