PublishViewController.swift 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. //
  2. // PublishViewController.swift
  3. // RainbowPlanet
  4. //
  5. // Created by Christopher on 2019/6/18.
  6. // Copyright © 2019 RainbowPlanet. All rights reserved.
  7. //
  8. import UIKit
  9. import JXSegmentedView
  10. class PublishViewController: BaseViewController {
  11. // 视频选择页参数配置类
  12. var mediaConfig: AliyunMediaConfig {
  13. //默认配置
  14. let mediaConfig = AliyunMediaConfig.default()
  15. mediaConfig?.minDuration = 3.0
  16. mediaConfig?.maxDuration = 60.0
  17. mediaConfig?.fps = 25
  18. mediaConfig?.gop = 5
  19. mediaConfig?.cutMode = AliyunMediaCutMode.scaleAspectFill
  20. mediaConfig?.videoOnly = false
  21. mediaConfig?.backgroundColor = UIColor.black
  22. return mediaConfig!
  23. }
  24. // 裁剪页参数配置类
  25. var cropMediaConfig: AliyunMediaConfig {
  26. //默认配置
  27. let cropMediaConfig = AliyunMediaConfig.default()
  28. cropMediaConfig?.minDuration = 3.0
  29. cropMediaConfig?.maxDuration = 60.0
  30. cropMediaConfig?.fps = 25
  31. cropMediaConfig?.gop = 5
  32. cropMediaConfig?.cutMode = AliyunMediaCutMode.scaleAspectFill
  33. cropMediaConfig?.videoOnly = false
  34. cropMediaConfig?.backgroundColor = UIColor.black
  35. return cropMediaConfig!
  36. }
  37. override func viewDidLoad() {
  38. super.viewDidLoad()
  39. setupViews()
  40. setupLayouts()
  41. setupData()
  42. }
  43. override func setupViews() {
  44. view.addSubview(listContainerView)
  45. view.addSubview(segmentedView)
  46. }
  47. override func setupLayouts() {
  48. listContainerView.snp.makeConstraints { (make) in
  49. make.top.left.right.equalToSuperview()
  50. make.bottom.equalToSuperview()
  51. }
  52. segmentedView.snp.makeConstraints { (make) in
  53. make.height.equalTo(48)
  54. make.left.equalTo(0)
  55. make.right.equalTo(0)
  56. make.bottom.equalTo(-kSafeTabBarHeight)
  57. }
  58. }
  59. override func setupData() {
  60. }
  61. //1.初始化JXSegmentedViewx
  62. private lazy var segmentedView: JXSegmentedView = {
  63. let segmentedView = JXSegmentedView()
  64. segmentedView.delegate = self
  65. segmentedView.dataSource = segmentedDataSourceAlbum
  66. segmentedView.indicators = [indicator]
  67. segmentedView.contentScrollView = listContainerView.scrollView
  68. segmentedView.selectItemAt(index: 0)
  69. segmentedView.defaultSelectedIndex = 0
  70. return segmentedView
  71. }()
  72. //2.初始化dataSource
  73. private lazy var segmentedDataSourceAlbum: JXSegmentedTitleDataSource = {
  74. let segmentedDataSource = JXSegmentedTitleDataSource()
  75. segmentedDataSource.titles = ["相册","拍视频","拍照"]
  76. segmentedDataSource.isTitleColorGradientEnabled = true
  77. segmentedDataSource.isItemSpacingAverageEnabled = true
  78. segmentedDataSource.isTitleZoomEnabled = true
  79. segmentedDataSource.titleNormalColor = kbbbbbbColor
  80. segmentedDataSource.titleSelectedColor = k333333Color
  81. segmentedDataSource.titleNormalFont = kRegularFont14!
  82. segmentedDataSource.titleSelectedFont = kBoldFont22
  83. segmentedDataSource.isTitleStrokeWidthEnabled = true
  84. //reloadData(selectedIndex:)方法一定要调用,方法内部会刷新数据源数组
  85. segmentedDataSource.reloadData(selectedIndex: 0)
  86. return segmentedDataSource
  87. }()
  88. private lazy var segmentedDataSourceVideo: JXSegmentedTitleDataSource = {
  89. let segmentedDataSource = JXSegmentedTitleDataSource()
  90. segmentedDataSource.titles = ["相册","拍视频","拍照"]
  91. segmentedDataSource.isTitleColorGradientEnabled = true
  92. segmentedDataSource.isItemSpacingAverageEnabled = true
  93. segmentedDataSource.isTitleZoomEnabled = true
  94. segmentedDataSource.titleNormalColor = kffffffColor
  95. segmentedDataSource.titleSelectedColor = kffffffColor
  96. segmentedDataSource.titleNormalFont = kRegularFont14!
  97. segmentedDataSource.titleSelectedFont = kBoldFont22
  98. segmentedDataSource.isTitleStrokeWidthEnabled = true
  99. //reloadData(selectedIndex:)方法一定要调用,方法内部会刷新数据源数组
  100. return segmentedDataSource
  101. }()
  102. //3.初始化指示器indicator
  103. private lazy var indicator: JXSegmentedIndicatorRainbowLineView = {
  104. let indicator = JXSegmentedIndicatorRainbowLineView()
  105. indicator.indicatorColors = [k62CC74Color,.white,.white]
  106. indicator.indicatorHeight = 3
  107. indicator.indicatorWidth = 20
  108. indicator.verticalOffset = 8
  109. return indicator
  110. }()
  111. //4.初始化JXSegmentedListContainerView
  112. private lazy var listContainerView: JXSegmentedListContainerView = {
  113. let listContainerView = JXSegmentedListContainerView(dataSource: self)
  114. listContainerView.didAppearPercent = 0.01
  115. listContainerView.defaultSelectedIndex = 0
  116. listContainerView.scrollView.isScrollEnabled = false
  117. return listContainerView
  118. }()
  119. }
  120. // MARK: - JXSegmentedViewDelegate
  121. extension PublishViewController : JXSegmentedViewDelegate {
  122. //点击选中或者滚动选中都会调用该方法。适用于只关心选中事件,而不关心具体是点击还是滚动选中的情况。
  123. func segmentedView(_ segmentedView: JXSegmentedView, didSelectedItemAt index: Int) {
  124. switch index {
  125. case 0:
  126. self.segmentedView.backgroundColor = .white
  127. self.segmentedDataSourceAlbum.reloadData(selectedIndex: 0)
  128. self.segmentedView.dataSource = segmentedDataSourceAlbum
  129. self.segmentedView.reloadData()
  130. statusBarStyle = .default
  131. case 1:
  132. self.segmentedView.backgroundColor = .clear
  133. self.segmentedDataSourceVideo.reloadData(selectedIndex: 1)
  134. self.segmentedView.dataSource = segmentedDataSourceVideo
  135. self.segmentedView.reloadData()
  136. statusBarStyle = .lightContent
  137. case 2:
  138. self.segmentedView.backgroundColor = .clear
  139. self.segmentedDataSourceVideo.reloadData(selectedIndex: 2)
  140. self.segmentedView.dataSource = segmentedDataSourceVideo
  141. self.segmentedView.reloadData()
  142. statusBarStyle = .lightContent
  143. default:
  144. break
  145. }
  146. }
  147. // 点击选中的情况才会调用该方法
  148. func segmentedView(_ segmentedView: JXSegmentedView, didClickSelectedItemAt index: Int) {
  149. //传递didClickSelectedItemAt事件给listContainerView,必须调用!!!
  150. listContainerView.didClickSelectedItem(at: index)
  151. }
  152. // 滚动选中的情况才会调用该方法(未支持滚动选中)
  153. func segmentedView(_ segmentedView: JXSegmentedView, didScrollSelectedItemAt index: Int) {
  154. print("\n------滚动选中\(index)")
  155. }
  156. // 正在滚动中的回调
  157. func segmentedView(_ segmentedView: JXSegmentedView, scrollingFrom leftIndex: Int, to rightIndex: Int, percent: CGFloat) {
  158. self.segmentedView.backgroundColor = .clear
  159. //传递scrolling事件给listContainerView,必须调用!!!
  160. listContainerView.segmentedViewScrolling(from: leftIndex, to: rightIndex, percent: percent, selectedIndex: segmentedView.selectedIndex)
  161. }
  162. /// 是否允许点击选中目标index的item
  163. func segmentedView(_ segmentedView: JXSegmentedView, canClickItemAt index: Int) -> Bool {
  164. return true
  165. }
  166. }
  167. // MARK: - JXSegmentedListContainerViewDataSource
  168. extension PublishViewController :JXSegmentedListContainerViewDataSource {
  169. func numberOfLists(in listContainerView: JXSegmentedListContainerView) -> Int {
  170. if let titleDataSource = segmentedView.dataSource as? JXSegmentedBaseDataSource {
  171. return titleDataSource.dataSource.count
  172. }
  173. return 0
  174. }
  175. func listContainerView(_ listContainerView: JXSegmentedListContainerView, initListAt index: Int) -> JXSegmentedListContainerViewListDelegate {
  176. switch index {
  177. case 0:
  178. let mediaVc = KSMediaPickerController(maxVideoItemCount: 1, maxPictureItemCount: 9)
  179. mediaVc.dismissClosure = {
  180. [weak self] in
  181. self?.dismiss(animated: true, completion: nil)
  182. }
  183. mediaVc.cropClosure = {
  184. [weak self] (vItemModel) in
  185. self?.getAvUrlAssetAndCrop(vItemModel)
  186. }
  187. mediaVc.pubImgClosure = {
  188. [weak self] (imageArray) in
  189. let pubVc = PublishEditController()
  190. pubVc.imageArr = imageArray
  191. self?.navigationController?.pushViewController(pubVc, animated: true)
  192. }
  193. return mediaVc
  194. case 1:
  195. let videoVc = AliyunMagicCameraViewController()
  196. videoVc.quVideo = mediaConfig
  197. videoVc.dismissBlock = {
  198. [weak self] in
  199. self?.dismiss(animated: true, completion: nil)
  200. }
  201. videoVc.editBlock = {
  202. [weak self] in
  203. let editVc = AlivcShortVideoRoute.shared().alivcViewController(with: AlivcViewControlType.edit)
  204. self?.navigationController?.pushViewController(editVc, animated: true)
  205. }
  206. videoVc.hideSegmentBlock = {
  207. [weak self] (isHidden) in
  208. self?.segmentedView.isHidden = isHidden
  209. }
  210. return videoVc
  211. // let videoVc = PublishVideoRecorderController()
  212. // videoVc.dismissClosure = {
  213. // [weak self] in
  214. // self?.dismiss(animated: true, completion: nil)
  215. // }
  216. // videoVc.editClosure = {
  217. // [weak self] in
  218. // let editVc = PublishEditController()
  219. // self?.navigationController?.pushViewController(editVc, animated: true)
  220. // }
  221. // videoVc.hideSegmentClosure = {
  222. // [weak self] (isHidden) in
  223. // self?.segmentedView.isHidden = isHidden
  224. // }
  225. // return videoVc
  226. default:
  227. let photoVc = PublishTakePhotoController()
  228. photoVc.dismissClosure = {
  229. [weak self] in
  230. self?.dismiss(animated: true, completion: nil)
  231. }
  232. photoVc.pubImgTransClosure = {
  233. [weak self] (imageArray) in
  234. let pubVc = PublishEditController()
  235. pubVc.imageArr = imageArray
  236. self?.navigationController?.pushViewController(pubVc, animated: true)
  237. }
  238. return photoVc
  239. }
  240. }
  241. }
  242. // MARK: - AliyunCropViewControllerDelegate
  243. extension PublishViewController: AliyunCropViewControllerDelegate {
  244. func cropViewControllerExit() {
  245. self.navigationController?.popViewController(animated: true)
  246. }
  247. func cropViewControllerFinish(_ mediaInfo: AliyunMediaConfig!, viewController controller: UIViewController!) {
  248. print("----didFinishCrop")
  249. }
  250. }
  251. // MARK: -
  252. extension PublishViewController {
  253. // 先将PHAsset类型转换为AVURLAsset,并填充参数
  254. func getAvUrlAssetAndCrop(_ videoItem: KSMediaPickerItemModel) {
  255. let options = PHVideoRequestOptions()
  256. options.isNetworkAccessAllowed = true
  257. options.version = PHVideoRequestOptionsVersion.current
  258. let phAsset = videoItem.asset
  259. PHImageManager.default().requestAVAsset(forVideo: phAsset, options: options, resultHandler: {
  260. [weak self] avAsset, audioMix, info in
  261. let cpInfo = AliyunCompositionInfo()
  262. cpInfo.duration = avAsset!.avAssetVideoTrackDuration()
  263. let urlAsset = avAsset as? AVURLAsset
  264. cpInfo.asset = urlAsset
  265. cpInfo.sourcePath = urlAsset?.url.path
  266. cpInfo.type = AliyunCompositionInfoTypeVideo
  267. DispatchQueue.main.async {
  268. self?.jumpToCropVideoVc(cpInfo)
  269. }
  270. })
  271. }
  272. // 跳转至裁剪页
  273. func jumpToCropVideoVc(_ info: AliyunCompositionInfo) {
  274. var path: String? = nil
  275. var url: URL? = nil
  276. url = info.asset.url
  277. let root: String = AliyunPathManager.compositionRootDir()
  278. path = root.appending(AliyunPathManager.randomString())
  279. path = path?.appending(".mp4")
  280. handleOriginalSize(info)
  281. let cutConfig = AliyunMediaConfig.cut(withOutputPath: path, outputSize: cropMediaConfig.outputSize, minDuration: cropMediaConfig.minDuration, maxDuration: info.duration, cutMode: cropMediaConfig.cutMode, videoQuality: cropMediaConfig.videoQuality, fps: cropMediaConfig.fps, gop: cropMediaConfig.gop)
  282. cutConfig?.bitrate = cropMediaConfig.bitrate
  283. cutConfig?.sourcePath = url?.path
  284. cutConfig?.phImage = info.phImage
  285. cutConfig?.encodeMode = cropMediaConfig.encodeMode //编码
  286. cutConfig?.backgroundColor = cropMediaConfig.backgroundColor
  287. cutConfig?.cutMode = cropMediaConfig.cutMode
  288. cutConfig?.gpuCrop = cropMediaConfig.gpuCrop
  289. let cropVc = AliyunCropViewController()
  290. cropVc.cutInfo = cutConfig
  291. cropVc.delegate = self
  292. cropVc.fakeCrop = true
  293. self.navigationController?.pushViewController(cropVc, animated: true)
  294. }
  295. // 获取原比例的视频尺寸
  296. func handleOriginalSize(_ info: AliyunCompositionInfo?) {
  297. var size = CGSize.zero
  298. if info?.asset != nil {
  299. size = info?.asset.avAssetNaturalSize() ?? CGSize.zero
  300. } else {
  301. print("#Wrong:视频信息为nil")
  302. }
  303. let ratio = size.width / size.height
  304. if ratio > 0 {
  305. let height = cropMediaConfig.outputSize.width / ratio
  306. cropMediaConfig.outputSize = CGSize(width: cropMediaConfig.outputSize.width, height: height)
  307. }
  308. cropMediaConfig.outputSize = cropMediaConfig.fixedSize()
  309. }
  310. }