PhotoEditor+Gestures.swift 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. //
  2. // PhotoEditor+Gestures.swift
  3. // Photo Editor
  4. //
  5. // Created by Mohamed Hamed on 6/16/17.
  6. //
  7. //
  8. import Foundation
  9. import UIKit
  10. extension PhotoEditorViewController : UIGestureRecognizerDelegate {
  11. /**
  12. UIPanGestureRecognizer - Moving Objects
  13. Selecting transparent parts of the imageview won't move the object
  14. */
  15. @objc func panGesture(_ recognizer: UIPanGestureRecognizer) {
  16. if let view = recognizer.view {
  17. if view is UIImageView {
  18. //Tap only on visible parts on the image
  19. if recognizer.state == .began {
  20. for imageView in subImageViews(view: canvasImageView) {
  21. let location = recognizer.location(in: imageView)
  22. let alpha = imageView.alphaAtPoint(location)
  23. if alpha > 0 {
  24. imageViewToPan = imageView
  25. break
  26. }
  27. }
  28. }
  29. if imageViewToPan != nil {
  30. moveView(view: imageViewToPan!, recognizer: recognizer)
  31. }
  32. } else {
  33. moveView(view: view, recognizer: recognizer)
  34. }
  35. }
  36. }
  37. /**
  38. UIPinchGestureRecognizer - Pinching Objects
  39. If it's a UITextView will make the font bigger so it doen't look pixlated
  40. */
  41. @objc func pinchGesture(_ recognizer: UIPinchGestureRecognizer) {
  42. if let view = recognizer.view {
  43. if view is UITextView {
  44. let textView = view as! UITextView
  45. if textView.font!.pointSize * recognizer.scale < 90 {
  46. let font = UIFont(name: textView.font!.fontName, size: textView.font!.pointSize * recognizer.scale)
  47. textView.font = font
  48. let sizeToFit = textView.sizeThatFits(CGSize(width: UIScreen.main.bounds.size.width,
  49. height:CGFloat.greatestFiniteMagnitude))
  50. textView.bounds.size = CGSize(width: textView.intrinsicContentSize.width,
  51. height: sizeToFit.height)
  52. } else {
  53. let sizeToFit = textView.sizeThatFits(CGSize(width: UIScreen.main.bounds.size.width,
  54. height:CGFloat.greatestFiniteMagnitude))
  55. textView.bounds.size = CGSize(width: textView.intrinsicContentSize.width,
  56. height: sizeToFit.height)
  57. }
  58. textView.setNeedsDisplay()
  59. } else {
  60. view.transform = view.transform.scaledBy(x: recognizer.scale, y: recognizer.scale)
  61. }
  62. recognizer.scale = 1
  63. }
  64. }
  65. /**
  66. UIRotationGestureRecognizer - Rotating Objects
  67. */
  68. @objc func rotationGesture(_ recognizer: UIRotationGestureRecognizer) {
  69. if let view = recognizer.view {
  70. view.transform = view.transform.rotated(by: recognizer.rotation)
  71. recognizer.rotation = 0
  72. }
  73. }
  74. /**
  75. UITapGestureRecognizer - Taping on Objects
  76. Will make scale scale Effect
  77. Selecting transparent parts of the imageview won't move the object
  78. */
  79. @objc func tapGesture(_ recognizer: UITapGestureRecognizer) {
  80. if let view = recognizer.view {
  81. if view is UIImageView {
  82. //Tap only on visible parts on the image
  83. for imageView in subImageViews(view: canvasImageView) {
  84. let location = recognizer.location(in: imageView)
  85. let alpha = imageView.alphaAtPoint(location)
  86. if alpha > 0 {
  87. scaleEffect(view: imageView)
  88. break
  89. }
  90. }
  91. } else {
  92. scaleEffect(view: view)
  93. }
  94. }
  95. }
  96. /*
  97. Support Multiple Gesture at the same time
  98. */
  99. public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
  100. return true
  101. }
  102. public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
  103. return false
  104. }
  105. public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
  106. return false
  107. }
  108. @objc func screenEdgeSwiped(_ recognizer: UIScreenEdgePanGestureRecognizer) {
  109. if recognizer.state == .recognized {
  110. if !stickersVCIsVisible {
  111. addStickersViewController()
  112. }
  113. }
  114. }
  115. // to Override Control Center screen edge pan from bottom
  116. override public var prefersStatusBarHidden: Bool {
  117. return true
  118. }
  119. /**
  120. Scale Effect
  121. */
  122. func scaleEffect(view: UIView) {
  123. view.superview?.bringSubviewToFront(view)
  124. if #available(iOS 10.0, *) {
  125. let generator = UIImpactFeedbackGenerator(style: .heavy)
  126. generator.impactOccurred()
  127. }
  128. let previouTransform = view.transform
  129. UIView.animate(withDuration: 0.2,
  130. animations: {
  131. view.transform = view.transform.scaledBy(x: 1.2, y: 1.2)
  132. },
  133. completion: { _ in
  134. UIView.animate(withDuration: 0.2) {
  135. view.transform = previouTransform
  136. }
  137. })
  138. }
  139. /**
  140. Moving Objects
  141. delete the view if it's inside the delete view
  142. Snap the view back if it's out of the canvas
  143. */
  144. func moveView(view: UIView, recognizer: UIPanGestureRecognizer) {
  145. hideToolbar(hide: true)
  146. deleteView.isHidden = false
  147. view.superview?.bringSubviewToFront(view)
  148. let pointToSuperView = recognizer.location(in: self.view)
  149. view.center = CGPoint(x: view.center.x + recognizer.translation(in: canvasImageView).x,
  150. y: view.center.y + recognizer.translation(in: canvasImageView).y)
  151. recognizer.setTranslation(CGPoint.zero, in: canvasImageView)
  152. if let previousPoint = lastPanPoint {
  153. //View is going into deleteView
  154. if deleteView.frame.contains(pointToSuperView) && !deleteView.frame.contains(previousPoint) {
  155. if #available(iOS 10.0, *) {
  156. let generator = UIImpactFeedbackGenerator(style: .heavy)
  157. generator.impactOccurred()
  158. }
  159. UIView.animate(withDuration: 0.3, animations: {
  160. view.transform = view.transform.scaledBy(x: 0.25, y: 0.25)
  161. view.center = recognizer.location(in: self.canvasImageView)
  162. })
  163. }
  164. //View is going out of deleteView
  165. else if deleteView.frame.contains(previousPoint) && !deleteView.frame.contains(pointToSuperView) {
  166. //Scale to original Size
  167. UIView.animate(withDuration: 0.3, animations: {
  168. view.transform = view.transform.scaledBy(x: 4, y: 4)
  169. view.center = recognizer.location(in: self.canvasImageView)
  170. })
  171. }
  172. }
  173. lastPanPoint = pointToSuperView
  174. if recognizer.state == .ended {
  175. imageViewToPan = nil
  176. lastPanPoint = nil
  177. if isTyping == true {
  178. hideToolbar(hide: true)
  179. } else {
  180. hideToolbar(hide: false)
  181. }
  182. deleteView.isHidden = true
  183. let point = recognizer.location(in: self.view)
  184. if deleteView.frame.contains(point) { // Delete the view
  185. view.removeFromSuperview()
  186. if #available(iOS 10.0, *) {
  187. let generator = UINotificationFeedbackGenerator()
  188. generator.notificationOccurred(.success)
  189. }
  190. } else if !canvasImageView.bounds.contains(view.center) { //Snap the view back to canvasImageView
  191. UIView.animate(withDuration: 0.3, animations: {
  192. view.center = self.canvasImageView.center
  193. })
  194. }
  195. }
  196. }
  197. func subImageViews(view: UIView) -> [UIImageView] {
  198. var imageviews: [UIImageView] = []
  199. for imageView in view.subviews {
  200. if imageView is UIImageView {
  201. imageviews.append(imageView as! UIImageView)
  202. }
  203. }
  204. return imageviews
  205. }
  206. }