经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » iOS » 查看文章
iOS 10自定义相机功能
来源:jb51  时间:2019/4/22 8:37:58  对本文有异议

本文实例为大家分享了iOS 10自定义相机功能的具体代码,供大家参考,具体内容如下

直接上代码

  1. //
  2. // TGCameraVC.swift
  3. // TGPhotoPicker
  4. //
  5. // Created by targetcloud on 2017/7/25.
  6. // Copyright © 2017年 targetcloud. All rights reserved.
  7. //
  8. import UIKit
  9. import AVFoundation
  10. import Photos
  11. @available(iOS 10.0, *)
  12. class TGCameraVC: UIViewController {
  13. var callbackPicutureData: ((Data?) -> ())?
  14. private var device: AVCaptureDevice?
  15. private var input: AVCaptureDeviceInput?
  16. private var imageOutput: AVCapturePhotoOutput?
  17. private var session: AVCaptureSession?
  18. private var previewLayer: AVCaptureVideoPreviewLayer?
  19. fileprivate var showImageContainerView: UIView?
  20. fileprivate var showImageView: UIImageView?
  21. fileprivate var picData: Data?
  22. private var flashMode: AVCaptureFlashMode = .auto
  23. private weak var flashButton: UIButton?
  24. override func viewDidLoad() {
  25. super.viewDidLoad()
  26. setupCamera()
  27. setupUI()
  28. if #available(iOS 9.0, *) {
  29. let isVCBased = Bundle.main.infoDictionary?["UIViewControllerBasedStatusBarAppearance"] as? Bool ?? false
  30. if !isVCBased{
  31. UIApplication.shared.setStatusBarHidden(false, with: .none)
  32. }
  33. }else {
  34. UIApplication.shared.statusBarStyle = .lightContent
  35. UIApplication.shared.setStatusBarHidden(false, with: .none)
  36. }
  37. }
  38. override var prefersStatusBarHidden: Bool{
  39. return false
  40. }
  41. override var preferredStatusBarStyle: UIStatusBarStyle {
  42. return .lightContent
  43. }
  44. private func setupCamera() {
  45. AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo) { success in
  46. if !success {
  47. let alertVC = UIAlertController(title: TGPhotoPickerConfig.shared.cameraUsage, message: TGPhotoPickerConfig.shared.cameraUsageTip, preferredStyle: .actionSheet)
  48. alertVC.addAction(UIAlertAction(title: TGPhotoPickerConfig.shared.confirmTitle, style: .default, handler: nil))
  49. self.present(alertVC, animated: true, completion: nil)
  50. }
  51. }
  52. device = cameraWithPosistion(.back)
  53. input = try? AVCaptureDeviceInput(device: device)
  54. guard input != nil else {
  55. return
  56. }
  57. imageOutput = AVCapturePhotoOutput()
  58. session = AVCaptureSession()
  59. session?.beginConfiguration()
  60. session?.sessionPreset = TGPhotoPickerConfig.shared.sessionPreset
  61. if session!.canAddInput(input) {
  62. session!.addInput(input)
  63. }
  64. if session!.canAddOutput(imageOutput) {
  65. session!.addOutput(imageOutput)
  66. }
  67. previewLayer = AVCaptureVideoPreviewLayer(session: session)
  68. previewLayer?.frame = view.bounds
  69. previewLayer?.videoGravity = TGPhotoPickerConfig.shared.videoGravity
  70. view.layer.addSublayer(previewLayer!)
  71. session?.commitConfiguration()
  72. session?.startRunning()
  73. }
  74. private func cameraWithPosistion(_ position: AVCaptureDevicePosition) -> AVCaptureDevice {
  75. let type = AVCaptureDeviceType(rawValue: TGPhotoPickerConfig.shared.captureDeviceType.rawValue)
  76. return AVCaptureDevice.defaultDevice(withDeviceType: type, mediaType: AVMediaTypeVideo, position: position)
  77. }
  78. private func setupUI() {
  79. let takeButton = UIButton(frame: CGRect(x: 0, y: 0, width: TGPhotoPickerConfig.shared.takeWH, height: TGPhotoPickerConfig.shared.takeWH))
  80. takeButton.center = CGPoint(x: UIScreen.main.bounds.width / 2, y: UIScreen.main.bounds.height - TGPhotoPickerConfig.shared.buttonEdge.bottom)
  81. takeButton.setImage(UIImage.size(width: TGPhotoPickerConfig.shared.takeWH, height: TGPhotoPickerConfig.shared.takeWH).border(width: 3).border(color: .white).color(.clear).corner(radius: TGPhotoPickerConfig.shared.takeWH / 2).image +
  82. UIImage.size(width: TGPhotoPickerConfig.shared.takeWH - 10, height: TGPhotoPickerConfig.shared.takeWH - 10).color(UIColor(white: 0.95, alpha: 1) ).corner(radius: (TGPhotoPickerConfig.shared.takeWH - 10) / 2).image, for: .normal)
  83. takeButton.setImage(UIImage.size(width: TGPhotoPickerConfig.shared.takeWH, height: TGPhotoPickerConfig.shared.takeWH).border(width: 3).border(color: .white).color(.clear).corner(radius: TGPhotoPickerConfig.shared.takeWH / 2).image +
  84. UIImage.size(width: TGPhotoPickerConfig.shared.takeWH - 10, height: TGPhotoPickerConfig.shared.takeWH - 10).color(UIColor(white: 0.8, alpha: 1) ).corner(radius: (TGPhotoPickerConfig.shared.takeWH - 10) / 2).image, for: .highlighted)
  85. takeButton.addTarget(self, action: #selector(takePhotoAction), for: .touchUpInside)
  86. view.addSubview(takeButton)
  87. let cameraChangeButton = UIButton(frame: CGRect(x: 0, y: 0, width: TGPhotoPickerConfig.shared.takeWH * 0.6, height: TGPhotoPickerConfig.shared.takeWH * 0.6))
  88. cameraChangeButton.setImage(TGPhotoPickerConfig.getImageNo2x3xSuffix("camera"), for: .normal)
  89. cameraChangeButton.center = CGPoint(x: UIScreen.main.bounds.width - TGPhotoPickerConfig.shared.buttonEdge.right, y: takeButton.center.y)
  90. cameraChangeButton.addTarget(self, action: #selector(changeCameraPositionAction), for: .touchUpInside)
  91. cameraChangeButton.contentMode = .scaleAspectFit
  92. view.addSubview(cameraChangeButton)
  93. let flashChangeButton = UIButton(frame: CGRect(x: 0, y: 0, width: TGPhotoPickerConfig.shared.takeWH * 0.5, height: TGPhotoPickerConfig.shared.takeWH * 0.5))
  94. flashChangeButton.center = CGPoint(x: cameraChangeButton.center.x, y: TGPhotoPickerConfig.shared.buttonEdge.top)
  95. flashChangeButton.setImage(TGPhotoPickerConfig.getImageNo2x3xSuffix("flashauto"), for: .normal)
  96. flashChangeButton.addTarget(self, action: #selector(flashChangeAction), for: .touchUpInside)
  97. flashChangeButton.contentMode = .scaleAspectFit
  98. flashButton = flashChangeButton
  99. view.addSubview(flashChangeButton)
  100. let backButton = UIButton(frame: CGRect(x: 0, y: 0, width: TGPhotoPickerConfig.shared.takeWH * 0.4, height: TGPhotoPickerConfig.shared.takeWH * 0.4))
  101. backButton.center = CGPoint(x: TGPhotoPickerConfig.shared.buttonEdge.left , y: flashChangeButton.center.y)
  102. backButton.setImage(UIImage.size(width: TGPhotoPickerConfig.shared.takeWH * 0.4, height: TGPhotoPickerConfig.shared.takeWH * 0.4)
  103. .corner(radius: TGPhotoPickerConfig.shared.takeWH * 0.2)
  104. .color(.clear)
  105. .border(color: UIColor.white.withAlphaComponent(0.7))
  106. .border(width: TGPhotoPickerConfig.shared.isShowBorder ? TGPhotoPickerConfig.shared.checkboxLineW : 0)
  107. .image
  108. .with({ context in
  109. context.setLineCap(.round)
  110. UIColor.white.setStroke()
  111. context.setLineWidth(TGPhotoPickerConfig.shared.checkboxLineW)
  112. let WH = TGPhotoPickerConfig.shared.takeWH * 0.4
  113. context.move(to: CGPoint(x: WH * 0.6, y: WH * 0.2))
  114. context.addLine(to: CGPoint(x: WH * 0.35, y: WH * 0.5))
  115. context.move(to: CGPoint(x: WH * 0.35, y: WH * 0.5))
  116. context.addLine(to: CGPoint(x: WH * 0.6, y: WH * 0.8))
  117. context.strokePath()
  118. }), for: .normal)
  119. backButton.contentMode = .scaleAspectFit
  120. backButton.addTarget(self, action: #selector(backAction), for: .touchUpInside)
  121. view.addSubview(backButton)
  122. showImageContainerView = UIView(frame: view.bounds)
  123. showImageContainerView?.backgroundColor = TGPhotoPickerConfig.shared.previewBGColor
  124. view.addSubview(showImageContainerView!)
  125. let height = showImageContainerView!.bounds.height - TGPhotoPickerConfig.shared.takeWH - TGPhotoPickerConfig.shared.buttonEdge.bottom - TGPhotoPickerConfig.shared.previewPadding * 2
  126. showImageView = UIImageView(frame: CGRect(x: TGPhotoPickerConfig.shared.previewPadding, y: TGPhotoPickerConfig.shared.previewPadding * 2, width: showImageContainerView!.bounds.width - 2 * TGPhotoPickerConfig.shared.previewPadding, height: height))
  127. showImageView?.contentMode = .scaleAspectFit
  128. showImageContainerView?.addSubview(showImageView!)
  129. showImageContainerView?.isHidden = true
  130. let giveupButton = createImageOperatorButton(nil, CGPoint(x: TGPhotoPickerConfig.shared.takeWH * 1.5, y: showImageContainerView!.bounds.height - TGPhotoPickerConfig.shared.takeWH * 1.5), TGPhotoPickerConfig.shared.getCheckboxImage(true, true, .circle, TGPhotoPickerConfig.shared.takeWH * 0.7).unselect)
  131. giveupButton.addTarget(self, action: #selector(giveupImageAction), for: .touchUpInside)
  132. showImageContainerView?.addSubview(giveupButton)
  133. let ensureButton = createImageOperatorButton(nil, CGPoint(x: showImageContainerView!.bounds.width - TGPhotoPickerConfig.shared.takeWH * 1.5, y: showImageContainerView!.bounds.height - TGPhotoPickerConfig.shared.takeWH * 1.5), TGPhotoPickerConfig.shared.getCheckboxImage(true, false, .circle, TGPhotoPickerConfig.shared.takeWH * 0.7).select)
  134. ensureButton.addTarget(self, action: #selector(useImageAction), for: .touchUpInside)
  135. showImageContainerView?.addSubview(ensureButton)
  136. }
  137. private func createImageOperatorButton(_ title: String?, _ center: CGPoint, _ img: UIImage?) -> UIButton {
  138. let btn = UIButton(frame: CGRect(x: 0, y: 0, width: TGPhotoPickerConfig.shared.takeWH * 0.7, height: TGPhotoPickerConfig.shared.takeWH * 0.7))
  139. btn.center = center
  140. btn.setTitle(title, for: .normal)
  141. btn.setImage(img, for: .normal)
  142. btn.contentMode = .scaleAspectFit
  143. return btn
  144. }
  145. @objc private func flashChangeAction() {
  146. switch flashMode {
  147. case .auto:
  148. flashMode = .on
  149. flashButton?.setImage(TGPhotoPickerConfig.getImageNo2x3xSuffix("flash"), for: .normal)
  150. case .on:
  151. flashMode = .off
  152. flashButton?.setImage(TGPhotoPickerConfig.getImageNo2x3xSuffix("flashno"), for: .normal)
  153. case .off:
  154. flashMode = .auto
  155. flashButton?.setImage(TGPhotoPickerConfig.getImageNo2x3xSuffix("flashauto"), for: .normal)
  156. }
  157. }
  158. @objc private func backAction() {
  159. dismiss(animated: true, completion: nil)
  160. }
  161. @objc private func takePhotoAction() {
  162. let connection = imageOutput?.connection(withMediaType: AVMediaTypeVideo)
  163. guard connection != nil else {
  164. return
  165. }
  166. let photoSettings = AVCapturePhotoSettings()
  167. photoSettings.flashMode = flashMode
  168. imageOutput?.capturePhoto(with: photoSettings, delegate: self)
  169. }
  170. @objc private func changeCameraPositionAction() {
  171. let animation = CATransition()
  172. animation.duration = 0.5
  173. animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
  174. animation.type = TGPhotoPickerConfig.shared.transitionType
  175. let newDevice: AVCaptureDevice!
  176. let newInput: AVCaptureDeviceInput?
  177. let position = input?.device.position
  178. if position == .front {
  179. newDevice = cameraWithPosistion(.back)
  180. animation.subtype = kCATransitionFromLeft
  181. } else {
  182. newDevice = cameraWithPosistion(.front)
  183. animation.subtype = kCATransitionFromRight
  184. }
  185. newInput = try? AVCaptureDeviceInput(device: newDevice)
  186. guard newInput != nil else{
  187. return
  188. }
  189. previewLayer?.add(animation, forKey: nil)
  190. session?.beginConfiguration()
  191. session?.removeInput(input)
  192. if session!.canAddInput(newInput) {
  193. session?.addInput(newInput!)
  194. input = newInput
  195. } else {
  196. session?.addInput(input)
  197. }
  198. session?.commitConfiguration()
  199. }
  200. @objc private func giveupImageAction() {
  201. showImageView?.image = UIImage()
  202. showImageContainerView?.isHidden = true
  203. }
  204. @objc private func useImageAction() {
  205. callbackPicutureData?(picData)
  206. dismiss(animated: true, completion: nil)
  207. }
  208. }
  209. @available(iOS 10.0, *)
  210. extension TGCameraVC: AVCapturePhotoCaptureDelegate {
  211. func capture(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhotoSampleBuffer photoSampleBuffer: CMSampleBuffer?, previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) {
  212. if error != nil {
  213. print("error = \(String(describing: error?.localizedDescription))")
  214. } else {
  215. if let imageData = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: photoSampleBuffer!, previewPhotoSampleBuffer: previewPhotoSampleBuffer){
  216. picData = imageData
  217. showImageContainerView?.isHidden = false
  218. showImageView?.image = UIImage(data: imageData)
  219. if TGPhotoPickerConfig.shared.saveImageToPhotoAlbum{
  220. self.saveImageToPhotoAlbum(UIImage(data: imageData)!)
  221. }
  222. }
  223. }
  224. }
  225. fileprivate func saveImageToPhotoAlbum(_ savedImage:UIImage){
  226. UIImageWriteToSavedPhotosAlbum(savedImage, self, #selector(imageDidFinishSavingWithErrorContextInfo), nil)
  227. }
  228. @objc fileprivate func imageDidFinishSavingWithErrorContextInfo(image:UIImage,error:NSError?,contextInfo:UnsafeMutableRawPointer?){
  229. if canUseAlbum(){
  230. let msg = (error != nil) ? TGPhotoPickerConfig.shared.saveImageFailTip : TGPhotoPickerConfig.shared.saveImageSuccessTip
  231. let alert = UIAlertView(title: TGPhotoPickerConfig.shared.saveImageTip, message: msg, delegate: self, cancelButtonTitle: TGPhotoPickerConfig.shared.confirmTitle)
  232. alert.show()
  233. }
  234. }
  235. fileprivate func canUseAlbum()-> Bool{
  236. if PHPhotoLibrary.authorizationStatus() != PHAuthorizationStatus.authorized {
  237. let alertView = UIAlertView(title: TGPhotoPickerConfig.shared.PhotoLibraryUsage, message: TGPhotoPickerConfig.shared.PhotoLibraryUsageTip, delegate: nil, cancelButtonTitle: TGPhotoPickerConfig.shared.confirmTitle, otherButtonTitles: TGPhotoPickerConfig.shared.cancelTitle)
  238. alertView.tag = TGPhotoPickerConfig.shared.alertViewTag
  239. alertView.show()
  240. return false
  241. }else{
  242. return true
  243. }
  244. }
  245. }
  246.  

效果如下

完整使用DEMO见:点击打开链接

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持w3xue。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号