NCViewerImageContentTransformers.swift 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. //
  2. // ContentTransformers.swift
  3. // Nextcloud
  4. //
  5. // Created by Suraj Thomas K on 7/17/18 Copyright © 2018 Al Tayer Group LLC..
  6. // Modify for Nextcloud by Marino Faggiana on 04/03/2020.
  7. //
  8. // Author Marino Faggiana <marino.faggiana@nextcloud.com>
  9. //
  10. // This program is free software: you can redistribute it and/or modify
  11. // it under the terms of the GNU General Public License as published by
  12. // the Free Software Foundation, either version 3 of the License, or
  13. // (at your option) any later version.
  14. //
  15. // This program is distributed in the hope that it will be useful,
  16. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. // GNU General Public License for more details.
  19. //
  20. // You should have received a copy of the GNU General Public License
  21. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. //
  23. /**
  24. Content transformer used for transition between media item views.
  25. - parameter contentView: The content view on which transform corresponding to the position has to be applied.
  26. - parameter position: Current position for the passed content view.
  27. - note:
  28. The trasnform to be applied on the contentView has to be dependent on the position passed.
  29. The position value can be -ve, 0.0 or positive.
  30. Try to visualize content views at -1.0[previous]=>0.0[current]=>1.0[next].
  31. 1. When position is -1.0, the content view should be at the place meant for previous view.
  32. 2. When the position is 0.0, the transform applied on the content view should make it visible full screen at origin.
  33. 3. When position is 1.0, the content view should be at the place meant for next view.
  34. Be mindful of the drawing order, when designing new transitions.
  35. */
  36. public typealias NCViewerImageContentTransformer = (_ contentView: UIView, _ position: CGFloat) -> Void
  37. // MARK: - Default Transitions
  38. /// An enumeration to hold default content transformers
  39. public enum NCViewerImageDefaultContentTransformers {
  40. /**
  41. Horizontal move-in-out content transformer.
  42. - Requires:
  43. * GestureDirection: Horizontal
  44. */
  45. public static let horizontalMoveInOut: NCViewerImageContentTransformer = { contentView, position in
  46. let widthIncludingGap = contentView.bounds.size.width + NCViewerImageContentView.interItemSpacing
  47. contentView.transform = CGAffineTransform(translationX: widthIncludingGap * position, y: 0.0)
  48. }
  49. /**
  50. Vertical move-in-out content transformer.
  51. - Requires:
  52. * GestureDirection: Vertical
  53. */
  54. public static let verticalMoveInOut: NCViewerImageContentTransformer = { contentView, position in
  55. let heightIncludingGap = contentView.bounds.size.height + NCViewerImageContentView.interItemSpacing
  56. contentView.transform = CGAffineTransform(translationX: 0.0, y: heightIncludingGap * position)
  57. }
  58. /**
  59. Horizontal slide-out content transformer.
  60. - Requires:
  61. * GestureDirection: Horizontal
  62. * DrawOrder: PreviousToNext
  63. */
  64. public static let horizontalSlideOut: NCViewerImageContentTransformer = { contentView, position in
  65. var scale: CGFloat = 1.0
  66. if position < -0.5 {
  67. scale = 0.9
  68. } else if -0.5...0.0 ~= Double(position) {
  69. scale = 1.0 + (position * 0.2)
  70. }
  71. var transform = CGAffineTransform(scaleX: scale, y: scale)
  72. let widthIncludingGap = contentView.bounds.size.width + NCViewerImageContentView.interItemSpacing
  73. let x = position >= 0.0 ? widthIncludingGap * position : 0.0
  74. transform = transform.translatedBy(x: x, y: 0.0)
  75. contentView.transform = transform
  76. let margin: CGFloat = 0.0000001
  77. contentView.isHidden = ((1.0-margin)...(1.0+margin) ~= abs(position))
  78. }
  79. /**
  80. Vertical slide-out content transformer.
  81. - Requires:
  82. * GestureDirection: Vertical
  83. * DrawOrder: PreviousToNext
  84. */
  85. public static let verticalSlideOut: NCViewerImageContentTransformer = { contentView, position in
  86. var scale: CGFloat = 1.0
  87. if position < -0.5 {
  88. scale = 0.9
  89. } else if -0.5...0.0 ~= Double(position) {
  90. scale = 1.0 + (position * 0.2)
  91. }
  92. var transform = CGAffineTransform(scaleX: scale, y: scale)
  93. let heightIncludingGap = contentView.bounds.size.height + NCViewerImageContentView.interItemSpacing
  94. let y = position >= 0.0 ? heightIncludingGap * position : 0.0
  95. transform = transform.translatedBy(x: 0.0, y: y)
  96. contentView.transform = transform
  97. let margin: CGFloat = 0.0000001
  98. contentView.isHidden = ((1.0-margin)...(1.0+margin) ~= abs(position))
  99. }
  100. /**
  101. Horizontal slide-in content transformer.
  102. - Requires:
  103. * GestureDirection: Horizontal
  104. * DrawOrder: NextToPrevious
  105. */
  106. public static let horizontalSlideIn: NCViewerImageContentTransformer = { contentView, position in
  107. var scale: CGFloat = 1.0
  108. if position > 0.5 {
  109. scale = 0.9
  110. } else if 0.0...0.5 ~= Double(position) {
  111. scale = 1.0 - (position * 0.2)
  112. }
  113. var transform = CGAffineTransform(scaleX: scale, y: scale)
  114. let widthIncludingGap = contentView.bounds.size.width + NCViewerImageContentView.interItemSpacing
  115. let x = position > 0.0 ? 0.0 : widthIncludingGap * position
  116. transform = transform.translatedBy(x: x, y: 0.0)
  117. contentView.transform = transform
  118. let margin: CGFloat = 0.0000001
  119. contentView.isHidden = ((1.0-margin)...(1.0+margin) ~= abs(position))
  120. }
  121. /**
  122. Vertical slide-in content transformer.
  123. - Requires:
  124. * GestureDirection: Vertical
  125. * DrawOrder: NextToPrevious
  126. */
  127. public static let verticalSlideIn: NCViewerImageContentTransformer = { contentView, position in
  128. var scale: CGFloat = 1.0
  129. if position > 0.5 {
  130. scale = 0.9
  131. } else if 0.0...0.5 ~= Double(position) {
  132. scale = 1.0 - (position * 0.2)
  133. }
  134. var transform = CGAffineTransform(scaleX: scale, y: scale)
  135. let heightIncludingGap = contentView.bounds.size.height + NCViewerImageContentView.interItemSpacing
  136. let y = position > 0.0 ? 0.0 : heightIncludingGap * position
  137. transform = transform.translatedBy(x: 0.0, y: y)
  138. contentView.transform = transform
  139. let margin: CGFloat = 0.0000001
  140. contentView.isHidden = ((1.0-margin)...(1.0+margin) ~= abs(position))
  141. }
  142. /**
  143. Horizontal zoom-in-out content transformer.
  144. - Requires:
  145. * GestureDirection: Horizontal
  146. */
  147. public static let horizontalZoomInOut: NCViewerImageContentTransformer = { contentView, position in
  148. let minScale: CGFloat = 0.5
  149. // Scale factor is used to reduce the scale animation speed.
  150. let scaleFactor: CGFloat = 0.5
  151. var scale: CGFloat = CGFloat.maximum(minScale, 1.0 - abs(position * scaleFactor))
  152. // Actual gap will be scaleFactor * 0.5 times of contentView.bounds.size.width.
  153. let actualGap = contentView.bounds.size.width * scaleFactor * 0.5
  154. let gapCorrector = NCViewerImageContentView.interItemSpacing - actualGap
  155. let widthIncludingGap = contentView.bounds.size.width + gapCorrector
  156. let translation = (widthIncludingGap * position)/scale
  157. var transform = CGAffineTransform(scaleX: scale, y: scale)
  158. transform = transform.translatedBy(x: translation, y: 0.0)
  159. contentView.transform = transform
  160. }
  161. /**
  162. Vertical zoom-in-out content transformer.
  163. - Requires:
  164. * GestureDirection: Vertical
  165. */
  166. public static let verticalZoomInOut: NCViewerImageContentTransformer = { contentView, position in
  167. let minScale: CGFloat = 0.5
  168. // Scale factor is used to reduce the scale animation speed.
  169. let scaleFactor: CGFloat = 0.5
  170. let scale: CGFloat = CGFloat.maximum(minScale, 1.0 - abs(position * scaleFactor))
  171. // Actual gap will be scaleFactor * 0.5 times of contentView.bounds.size.height.
  172. let actualGap = contentView.bounds.size.height * scaleFactor * 0.5
  173. let gapCorrector = NCViewerImageContentView.interItemSpacing - actualGap
  174. let heightIncludingGap = contentView.bounds.size.height + gapCorrector
  175. let translation = (heightIncludingGap * position)/scale
  176. var transform = CGAffineTransform(scaleX: scale, y: scale)
  177. transform = transform.translatedBy(x: 0.0, y: translation)
  178. contentView.transform = transform
  179. }
  180. }