LNVideoPreviewCell.swift 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. //
  2. // LNVideoPreviewCell.swift
  3. // Lanu
  4. //
  5. // Created by OneeChan on 2025/12/11.
  6. //
  7. import Foundation
  8. import UIKit
  9. import SnapKit
  10. protocol LNVideoPreviewCellDelegate: NSObject {
  11. func onVideoPreviewCellDragToDismiss(cell: LNVideoPreviewCell)
  12. }
  13. class LNVideoPreviewCell: UICollectionViewCell {
  14. private let videoPlayer = LNVideoPlayerView()
  15. private let indicator = UIActivityIndicatorView(style: .large)
  16. private var panGesture: UIPanGestureRecognizer?
  17. private var touchBeginPoint: CGPoint = .zero
  18. private var lastMove: CGPoint = .zero
  19. private let dragScaleMin = 0.4
  20. private let dragScaleOffsetY = UIScreen.main.bounds.height * 0.5
  21. private let dragAlphaOffsetY = 150.0
  22. private var curUrl: String?
  23. weak var delegate: LNVideoPreviewCellDelegate?
  24. override init(frame: CGRect) {
  25. super.init(frame: frame)
  26. setupViews()
  27. setupGesture()
  28. }
  29. func update(url: String, coverUrl: String?) {
  30. indicator.startAnimating()
  31. videoPlayer.loadVideo(url, coverUrl: coverUrl)
  32. }
  33. func stop() {
  34. videoPlayer.stop()
  35. }
  36. required init?(coder: NSCoder) {
  37. fatalError("init(coder:) has not been implemented")
  38. }
  39. }
  40. extension LNVideoPreviewCell {
  41. @objc
  42. private func handlePan(_ gesture: UIPanGestureRecognizer) {
  43. let position = gesture.translation(in: self)
  44. switch gesture.state {
  45. case .began:
  46. touchBeginPoint = position
  47. break
  48. case .changed:
  49. lastMove = gesture.velocity(in: self)
  50. var frame = contentView.frame
  51. frame.origin.y = position.y - touchBeginPoint.y
  52. frame.origin.x = position.x - touchBeginPoint.x
  53. contentView.frame = frame
  54. let progress = (frame.origin.y / dragAlphaOffsetY).bounded(min: 0, max: 1.0)
  55. superview?.backgroundColor = .black.withAlphaComponent(1 - progress)
  56. let scale = 1 - (frame.origin.y / dragScaleOffsetY).bounded(min: 0, max: 1.0) * (1 - dragScaleMin)
  57. videoPlayer.transform = .init(scaleX: scale, y: scale)
  58. break
  59. default:
  60. if lastMove.y > 0 {
  61. var frame = contentView.frame
  62. frame.origin.y = bounds.height
  63. UIView.animate(withDuration: 0.25) { [weak self] in
  64. guard let self else { return }
  65. contentView.frame = frame
  66. superview?.backgroundColor = .clear
  67. } completion: { [weak self] _ in
  68. guard let self else { return }
  69. delegate?.onVideoPreviewCellDragToDismiss(cell: self)
  70. }
  71. } else {
  72. UIView.animate(withDuration: 0.25) { [weak self] in
  73. guard let self else { return }
  74. contentView.frame = bounds
  75. superview?.backgroundColor = .black
  76. videoPlayer.transform = .identity
  77. }
  78. }
  79. break
  80. }
  81. }
  82. }
  83. extension LNVideoPreviewCell: LNVideoPlayerViewDelegate {
  84. func onVideoDidLoad(view: LNVideoPlayerView) {
  85. indicator.stopAnimating()
  86. videoPlayer.start()
  87. }
  88. }
  89. extension LNVideoPreviewCell: UIGestureRecognizerDelegate {
  90. override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
  91. guard let pan = gestureRecognizer as? UIPanGestureRecognizer else {
  92. return true
  93. }
  94. let velocity = pan.velocity(in: self)
  95. return abs(velocity.y) > abs(velocity.x)
  96. }
  97. }
  98. extension LNVideoPreviewCell {
  99. private func setupViews() {
  100. videoPlayer.showCover = false
  101. videoPlayer.loop = true
  102. videoPlayer.delegate = self
  103. videoPlayer.backgroundColor = .clear
  104. videoPlayer.playButtonSize = 56
  105. contentView.addSubview(videoPlayer)
  106. videoPlayer.snp.makeConstraints { make in
  107. make.horizontalEdges.equalToSuperview()
  108. make.verticalEdges.equalToSuperview()
  109. }
  110. }
  111. private func setupGesture() {
  112. let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
  113. pan.delegate = self
  114. pan.isEnabled = true
  115. pan.maximumNumberOfTouches = 1
  116. contentView.addGestureRecognizer(pan)
  117. panGesture = pan
  118. }
  119. }