PQEditMusicSearchController.swift 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. //
  2. // PQEditMusicSearchController.swift
  3. // BFFramework
  4. //
  5. // Created by ak on 2021/8/7.
  6. // 功能:显示编辑界中搜索音乐界面
  7. import Foundation
  8. class PQEditMusicSearchController: PQBaseViewController {
  9. // 当前播放的音乐
  10. var currentPlayData: PQVoiceModel?
  11. // 当前播放的视频
  12. var playerItem: AVPlayerItem?
  13. // 左边距离
  14. let leftMargin: CGFloat = 47
  15. // 搜索拦高度
  16. let searchTFH: CGFloat = 37
  17. // 热搜数据
  18. var hotList: [Any] = Array<Any>.init()
  19. // 按钮点击的回调
  20. var btnClickHandle: ((_ sender: UIButton, _ bgmData: Any?) -> Void)?
  21. lazy var avPlayer: AVPlayer = {
  22. let avPlayer = AVPlayer()
  23. PQNotification.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: avPlayer.currentItem, queue: .main) { [weak self] notify in
  24. BFLog(message: "AVPlayerItemDidPlayToEndTime = \(notify)")
  25. avPlayer.seek(to: CMTime(value: CMTimeValue((self?.currentPlayData?.startTime ?? 0) * 1000), timescale: CMTimeScale(playerTimescale)))
  26. // avPlayer.play()
  27. self?.playStuckPointMusic(itemData: nil)
  28. }
  29. // PQNotification.addObserver(forName: .AVPlayerItemNewErrorLogEntry, object: avPlayer.currentItem, queue: .main) { notify in
  30. // BFLog(message: "AVPlayerItemNewErrorLogEntry = \(notify)")
  31. // }
  32. // PQNotification.addObserver(forName: .AVPlayerItemFailedToPlayToEndTime, object: avPlayer.currentItem, queue: .main) { notify in
  33. // BFLog(message: "AVPlayerItemFailedToPlayToEndTime = \(notify)")
  34. // }
  35. // PQNotification.addObserver(forName: .AVPlayerItemPlaybackStalled, object: avPlayer.currentItem, queue: .main) { notify in
  36. // BFLog(message: "AVPlayerItemPlaybackStalled = \(notify)")
  37. // }
  38. // avPlayer.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: CMTimeScale(playerTimescale)), queue: .main) { [weak self] cmTime in
  39. // BFLog(message: "addPeriodicTimeObserver = \(cmTime)")
  40. // }
  41. return avPlayer
  42. }()
  43. // 输入框清空按钮
  44. lazy var clearBtn: UIButton = {
  45. let clearBtn = UIButton(type: .custom)
  46. clearBtn.setImage(UIImage().BF_Image(named: "icon_search_delete"), for: .normal)
  47. clearBtn.frame = CGRect(x: 0, y: 0, width: 28, height: 32)
  48. clearBtn.tag = 1
  49. clearBtn.addTarget(self, action: #selector(btnClick(sender:)), for: .touchUpInside)
  50. clearBtn.isHidden = true
  51. return clearBtn
  52. }()
  53. // 搜索框
  54. lazy var searchTF: UITextField = {
  55. let searchTF = UITextField(frame: CGRect(x: leftMargin, y: cDevice_iPhoneStatusBarHei, width: cScreenWidth - leftMargin * 2, height: searchTFH))
  56. searchTF.font = UIFont.systemFont(ofSize: 17)
  57. searchTF.backgroundColor = PQBFConfig.shared.otherTintColor
  58. searchTF.attributedPlaceholder = NSAttributedString(string: "搜索歌曲名称/歌手", attributes: [.foregroundColor: UIColor.hexColor(hexadecimal: "#BDBDBD"), .font: UIFont.systemFont(ofSize: 14)])
  59. searchTF.textColor = PQBFConfig.shared.styleTitleColor
  60. searchTF.addCorner(corner: searchTFH / 2)
  61. searchTF.leftViewMode = .always
  62. let leftView = UIView(frame: CGRect(x: 0, y: 0, width: 35, height: 32))
  63. let imageView = UIImageView(image: UIImage().BF_Image(named: "icon_search_s"))
  64. imageView.frame = CGRect(x: 15, y: 8, width: 16, height: 16)
  65. leftView.addSubview(imageView)
  66. searchTF.leftView = leftView
  67. searchTF.delegate = self
  68. searchTF.rightViewMode = .always
  69. let rightView = UIView(frame: CGRect(x: 0, y: 0, width: 40, height: 32))
  70. rightView.addSubview(clearBtn)
  71. searchTF.rightView = rightView
  72. searchTF.delegate = self
  73. searchTF.returnKeyType = .search
  74. searchTF.addTarget(self, action: #selector(editingChanged), for: .editingChanged)
  75. return searchTF
  76. }()
  77. /// 搜索控制器
  78. lazy var searchController: PQStuckPointMusicSearchController = {
  79. let searchController = PQStuckPointMusicSearchController()
  80. searchController.cellHight = cDefaultMargin * 8
  81. searchController.updateViewFrame(newFrame: CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei + cDefaultMargin * 2, width: view.frame.width, height: view.frame.height - (cDevice_iPhoneNavBarAndStatusBarHei + cDefaultMargin * 2)))
  82. searchController.didSelectedHandle = { [weak self] isTagsClick, _, _, itemData in
  83. if !isTagsClick {
  84. self?.view.endEditing(true)
  85. if !(itemData is PQEmptyModel) {
  86. PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_shanyinApp_musicVideoPreview_musicSearchAudition, pageSource: .sp_shanyinApp_main, extParams: ["musicName":(itemData as? PQVoiceModel)?.musicName ?? "" ,"musicId":(itemData as? PQVoiceModel)?.musicId ?? ""], remindmsg: "")
  87. self?.playStuckPointMusic(itemData: itemData as? PQVoiceModel)
  88. }
  89. }
  90. }
  91. searchController.btnClickHandle = { [weak self] btn, bgmData in
  92. PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_shanyinApp_musicVideoPreview_musicSearchSelect, pageSource: .sp_shanyinApp_main, extParams: ["musicName":(bgmData as? PQVoiceModel)?.musicName ?? "" ,"musicId":(bgmData as? PQVoiceModel)?.musicId ?? ""], remindmsg: "")
  93. // 使用音乐
  94. self?.backBtnClick()
  95. if(self?.btnClickHandle != nil){
  96. self?.btnClickHandle!(btn,bgmData)
  97. }
  98. }
  99. searchController.scroDidScroHandle = { [weak self] in
  100. self?.view.endEditing(true)
  101. }
  102. searchController.contentType = .serach
  103. return searchController
  104. }()
  105. override func backBtnClick() {
  106. super.backBtnClick()
  107. avPlayer.pause()
  108. }
  109. deinit {
  110. PQNotification.removeObserver(self)
  111. avPlayer.currentItem?.removeObserver(self, forKeyPath: "status")
  112. avPlayer.currentItem?.removeObserver(self, forKeyPath: "error")
  113. avPlayer.pause()
  114. avPlayer.replaceCurrentItem(with: nil)
  115. playerItem = nil
  116. }
  117. override func viewWillAppear(_ animated: Bool) {
  118. super.viewDidAppear(animated)
  119. PQEventTrackViewModel.baseReportUpload(businessType: .bt_windowView, objectType: .ot_shanyinApp_musicVideoPreview_musicSearch, pageSource: .sp_shanyinApp_main, extParams: nil, remindmsg: "")
  120. }
  121. override func viewDidLoad() {
  122. super.viewDidLoad()
  123. view.addSubview(searchTF)
  124. searchTF.becomeFirstResponder()
  125. addChild(searchController)
  126. view.addSubview(searchController.view)
  127. leftButton(image: UIImage(named: "upload_delete"), tintColor: PQBFConfig.shared.styleTitleColor)
  128. //请求一下热门数据在没有搜索数据时显示
  129. PQStuckPointViewModel.stuckPointMusicPageList(tagId: 425, parentTagId: 0, pageNum: 1, videoCount: 0, imageCount: 0, totalDuration: 0) { [weak self] musicInfo, _ in
  130. if musicInfo.count > 0 {
  131. self?.searchController.hotList = musicInfo
  132. self?.searchController.configMusicListData(isRefresh: true, musicListData: musicInfo)
  133. }
  134. }
  135. }
  136. /// 按钮点击事件
  137. /// - Parameter sender: <#sender description#>
  138. /// - Returns: <#description#>
  139. @objc func btnClick(sender: UIButton) {
  140. switch sender.tag {
  141. case 1: // 清除
  142. searchTF.text = nil
  143. // emptyRemindView.isHidden = true
  144. clearBtn.isHidden = true
  145. default:
  146. break
  147. }
  148. }
  149. var avPlayerTimeObserver:Any?
  150. /// 播放音乐
  151. /// - Parameter itemData: <#itemData description#>
  152. func playStuckPointMusic(itemData: PQVoiceModel?, isClearCurrentMusic: Bool = false) {
  153. if itemData != nil, currentPlayData != itemData {
  154. if !isValidURL(url: itemData?.musicPath ?? "") {
  155. cShowHUB(superView: nil, msg: "本歌曲暂无伴奏版本哦~")
  156. return
  157. }
  158. avPlayer.pause()
  159. playerItem?.removeObserver(self, forKeyPath: "status")
  160. playerItem?.removeObserver(self, forKeyPath: "error")
  161. if avPlayerTimeObserver != nil {
  162. avPlayer.removeTimeObserver(avPlayerTimeObserver as Any)
  163. }
  164. playerItem = AVPlayerItem(url: URL(string: itemData?.musicPath ?? "")!)
  165. if (itemData?.endTime ?? 0) > 0, (itemData?.endTime ?? 0) > (itemData?.startTime ?? 0) {
  166. playerItem?.forwardPlaybackEndTime = CMTime(value: CMTimeValue((itemData?.endTime ?? 0) * playerTimescale), timescale: CMTimeScale(playerTimescale))
  167. }
  168. avPlayer.replaceCurrentItem(with: playerItem)
  169. playerItem?.addObserver(self, forKeyPath: "status", options: .new, context: nil)
  170. playerItem?.addObserver(self, forKeyPath: "error", options: .new, context: nil)
  171. avPlayer.seek(to: CMTime(value: CMTimeValue((itemData?.startTime ?? 0) * playerTimescale), timescale: CMTimeScale(playerTimescale)))
  172. avPlayer.play()
  173. avPlayerTimeObserver = avPlayer.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: 10), queue: DispatchQueue.global()) {[weak self] time in
  174. if fabs(CMTimeGetSeconds(time) - (itemData?.startTime ?? 0)) > 0.1 {
  175. self?.avPlayer.removeTimeObserver(self?.avPlayerTimeObserver as Any)
  176. self?.avPlayerTimeObserver = nil
  177. // 停止cell loading动画
  178. PQNotification.post(name: NSNotification.Name(rawValue: "MusicContentCellIconLoadingAnimationStop"), object: nil)
  179. }
  180. }
  181. // let player = TXVodPlayer()
  182. // let config = TXVodPlayConfig()
  183. // config.cacheFolderPath = videoCacheDirectory
  184. // config.maxCacheItems = 0
  185. // player.config = config
  186. //// player.vodDelegate = self
  187. // player.setRenderMode(.RENDER_MODE_FILL_EDGE)
  188. // player.startPlay("https://clipres.yishihui.com/longvideo/material/voice/prod/20210512/MUSIC_QQ_000T1Ws32MWrUj")
  189. currentPlayData = itemData
  190. } else if itemData != nil, avPlayer.rate == 0.0 {
  191. avPlayer.play()
  192. } else {
  193. avPlayer.pause()
  194. }
  195. if isClearCurrentMusic {
  196. avPlayer.pause()
  197. currentPlayData = nil
  198. }
  199. }
  200. }
  201. /// 音乐搜索相关
  202. extension PQEditMusicSearchController: UITextFieldDelegate {
  203. /// 点击输入框
  204. @objc func editingChanged() {
  205. if searchTF.text != nil, (searchTF.text?.count ?? 0) > 0, searchTF.markedTextRange == nil {
  206. if searchTF.text?.isSpace ?? false {
  207. return
  208. }
  209. // loadSearchData()
  210. clearBtn.isHidden = false
  211. }
  212. }
  213. /// 搜索
  214. @objc func loadSearchData() {
  215. if searchTF.text != nil, (searchTF.text?.count ?? 0) > 0, searchTF.text?.isSpace ?? false {
  216. cShowHUB(superView: nil, msg: "搜索内容不能为空")
  217. return
  218. }
  219. if searchTF.text != nil, (searchTF.text?.count ?? 0) > 0 {
  220. BFLog(message: "背景音乐--开始搜索背景音乐-1")
  221. searchController.loadSearchData(keyword: searchTF.text)
  222. }
  223. }
  224. /// 添加键盘监听
  225. /// - Returns: <#description#>
  226. func addKeyboardObserver() {
  227. // 监听键盘的显示和隐藏
  228. PQNotification.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
  229. PQNotification.addObserver(self, selector: #selector(keyboardWillHidden), name: UIResponder.keyboardWillHideNotification, object: nil)
  230. }
  231. /// 键盘显示
  232. /// - Parameter notification: <#notification description#>
  233. @objc func keyboardWillShow(notification: Notification) {
  234. let duration: TimeInterval = TimeInterval("\(notification.userInfo?["UIKeyboardAnimationDurationUserInfoKey"] ?? "1")") ?? 1
  235. UIView.animate(withDuration: duration) { [weak self] in
  236. self?.navTitleLabel?.alpha = 0
  237. self?.searchTF.frame = CGRect(x: cDefaultMargin * 5, y: (cDevice_iPhoneNavBarHei - (self?.searchTFH ?? 37.0)) / 2 + cDevice_iPhoneStatusBarHei, width: cScreenWidth - cDefaultMargin * 7, height: self?.searchTFH ?? 37.0)
  238. } completion: { _ in
  239. }
  240. searchController.view.isHidden = false
  241. hotList.forEach { item in
  242. if item is PQVoiceModel {
  243. (item as? PQVoiceModel)?.isSelected = false
  244. (item as? PQVoiceModel)?.isPlaying = false
  245. }
  246. }
  247. searchController.hotList = hotList
  248. playStuckPointMusic(itemData: nil)
  249. }
  250. /// 键盘将要隐藏
  251. @objc func keyboardWillHidden() {}
  252. /// 隐藏搜索界面
  253. /// - Returns: <#description#>
  254. func hiddenSearchController() {
  255. view.endEditing(true)
  256. UIView.animate(withDuration: 0.3) { [weak self] in
  257. self?.navTitleLabel?.alpha = 1
  258. self?.searchTF.frame = CGRect(x: self?.leftMargin ?? 0, y: cDevice_iPhoneNavBarAndStatusBarHei, width: cScreenWidth - (self?.leftMargin ?? 0) * 2, height: self?.searchTFH ?? 0)
  259. } completion: { _ in
  260. }
  261. clearBtn.isHidden = true
  262. searchController.view.isHidden = true
  263. playStuckPointMusic(itemData: nil)
  264. }
  265. override func touchesBegan(_: Set<UITouch>, with _: UIEvent?) {
  266. view.endEditing(true)
  267. }
  268. func textFieldShouldReturn(_ textField: UITextField) -> Bool {
  269. loadSearchData()
  270. PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_shanyinApp_musicVideoPreview_musicSearch, pageSource: .sp_shanyinApp_main, extParams: nil, remindmsg: "")
  271. view.endEditing(true)
  272. if textField.text == nil || (textField.text?.count ?? 0) <= 0 {
  273. cShowHUB(superView: nil, msg: "请先输入搜索内容")
  274. }
  275. return true
  276. }
  277. }
  278. extension PQEditMusicSearchController {
  279. override func observeValue(forKeyPath keyPath: String?, of object: Any?, change _: [NSKeyValueChangeKey: Any]?, context _: UnsafeMutableRawPointer?) {
  280. if object is AVPlayerItem, keyPath == "status" {
  281. BFLog(message: "AVPlayerItem - status = \((object as! AVPlayerItem).status.rawValue)")
  282. switch (object as! AVPlayerItem).status {
  283. case .unknown:
  284. break
  285. case .readyToPlay:
  286. break
  287. case .failed:
  288. break
  289. default:
  290. break
  291. }
  292. } else if object is AVPlayerItem, keyPath == "error" {
  293. BFLog(message: "AVPlayerItem - error = \(String(describing: (object as! AVPlayerItem).error))")
  294. }
  295. }
  296. }