PPVideoViewCell.swift 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. import UIKit
  2. import AVFoundation
  3. /**
  4. Cell representing video asset in Assets Collection Controller.
  5. */
  6. class PPVideoViewCell: PPPhotoViewCell {
  7. var videoLayer: AVPlayerLayer?
  8. fileprivate lazy var indicator: UIActivityIndicatorView? = {
  9. let activity = UIActivityIndicatorView()
  10. activity.style = .whiteLarge
  11. activity.hidesWhenStopped = true
  12. return activity
  13. }()
  14. fileprivate lazy var videoInfoView: UIView = {
  15. let videoInfoView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 0))
  16. videoInfoView.backgroundColor = UIColor.init(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.4)
  17. let videoImageView = UIImageView(image: DKImageResource.videoCameraIcon())
  18. videoInfoView.addSubview(videoImageView)
  19. videoImageView.center = CGPoint(x: videoImageView.bounds.width / 2 + 7, y: videoInfoView.bounds.height / 2)
  20. videoImageView.autoresizingMask = [.flexibleBottomMargin, .flexibleTopMargin]
  21. let videoDurationLabel = UILabel()
  22. videoDurationLabel.tag = -1
  23. videoDurationLabel.textAlignment = .right
  24. videoDurationLabel.font = UIFont.systemFont(ofSize: 12)
  25. videoDurationLabel.textColor = UIColor.white
  26. videoInfoView.addSubview(videoDurationLabel)
  27. videoDurationLabel.frame = CGRect(x: 0, y: 0, width: videoInfoView.bounds.width - 7, height: videoInfoView.bounds.height)
  28. videoDurationLabel.autoresizingMask = [.flexibleWidth, .flexibleHeight]
  29. return videoInfoView
  30. }()
  31. fileprivate var videoRequestID: PHImageRequestID?
  32. override init(frame: CGRect) {
  33. super.init(frame: frame)
  34. self.layer.addSublayer(videoInfoView.layer)
  35. let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(PPVideoViewCell.longPressed(_:)))
  36. self.addGestureRecognizer(longPressRecognizer)
  37. }
  38. required init?(coder aDecoder: NSCoder) {
  39. fatalError("init(coder:) has not been implemented")
  40. }
  41. func setVideo(_ videoAsset: PHAsset) {
  42. if (videoAsset != asset) {
  43. self.set(videoAsset)
  44. let videoDurationLabel = self.videoInfoView.viewWithTag(-1) as! UILabel
  45. if videoAsset.duration > 0 {
  46. let minutes: Int = Int(videoAsset.duration) / 60
  47. let seconds: Int = Int(round(videoAsset.duration)) % 60
  48. videoDurationLabel.text = String(format: "\(minutes):%02d", seconds)
  49. }
  50. } else {
  51. self.setupCheckmark()
  52. }
  53. }
  54. func loadVideo() {
  55. let options: PHVideoRequestOptions = PHVideoRequestOptions.init()
  56. options.version = .current
  57. options.isNetworkAccessAllowed = true
  58. options.deliveryMode = .fastFormat
  59. if backgroundView != nil {
  60. if !(indicator?.isDescendant(of: backgroundView!))! {
  61. self.insertSubview(indicator!, aboveSubview: backgroundView!)
  62. }
  63. }
  64. indicator?.frame = CGRect(x: (self.frame.size.width/2)-20, y: (self.frame.size.height/2)-20, width: 40, height: 40)
  65. indicator?.startAnimating()
  66. videoRequestID = PHCachingImageManager.default().requestAVAsset(forVideo: asset!, options: options)
  67. { avasset, audioMix, info in
  68. if avasset != nil {
  69. DispatchQueue.main.sync {
  70. let item = AVPlayerItem(asset: avasset!)
  71. let player = AVPlayer(playerItem: item)
  72. player.volume = 0.0
  73. let playerLayer = AVPlayerLayer(player: player)
  74. playerLayer.videoGravity = AVLayerVideoGravity.resize
  75. self.layer.insertSublayer(playerLayer, below: self.videoInfoView.layer)
  76. playerLayer.frame = self.bounds
  77. self.videoLayer = playerLayer
  78. self.startVideo()
  79. NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: item, queue: nil, using: { (_) in
  80. self.videoLayer?.player?.seek(to: CMTime.zero)
  81. self.startVideo()
  82. })
  83. }
  84. }
  85. }
  86. }
  87. func startVideo() {
  88. if videoLayer != nil {
  89. if self.videoLayer?.player?.currentItem?.status == .readyToPlay && self.indicator?.isAnimating == true {
  90. self.indicator?.stopAnimating()
  91. } else {
  92. if self.indicator?.isAnimating == false {
  93. self.indicator?.startAnimating()
  94. }
  95. }
  96. self.videoLayer?.player?.play()
  97. } else {
  98. loadVideo()
  99. }
  100. }
  101. func stopVideo() {
  102. if let videoLayer = videoLayer {
  103. self.indicator?.stopAnimating()
  104. videoLayer.player?.pause()
  105. } else {
  106. self.indicator?.stopAnimating()
  107. PHCachingImageManager.default().cancelImageRequest(videoRequestID!)
  108. NotificationCenter.default.removeObserver(self, name: .AVPlayerItemDidPlayToEndTime, object: nil)
  109. }
  110. }
  111. override func prepareForReuse() {
  112. super.prepareForReuse()
  113. if let videoLayer = videoLayer {
  114. videoLayer.removeFromSuperlayer()
  115. self.videoLayer = nil
  116. NotificationCenter.default.removeObserver(self, name: .AVPlayerItemDidPlayToEndTime, object: nil)
  117. }
  118. }
  119. override func layoutSubviews() {
  120. super.layoutSubviews()
  121. let height: CGFloat = 30
  122. self.videoInfoView.frame = CGRect(x: 0, y: self.contentView.bounds.height - height,
  123. width: self.contentView.bounds.width, height: height)
  124. videoLayer?.frame = bounds
  125. }
  126. private func is3DTouchAvailable() -> Bool
  127. {
  128. return self.traitCollection.forceTouchCapability == .available
  129. }
  130. @objc func longPressed(_ sender: UIGestureRecognizer)
  131. {
  132. if sender.state == .began {
  133. startVideo()
  134. }
  135. if sender.state == .ended {
  136. stopVideo()
  137. }
  138. }
  139. }