You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

132 lines
4.6 KiB

6 years ago
  1. // The MIT License (MIT)
  2. //
  3. // Copyright (c) 2016 Luke Zhao <me@lkzhao.com>
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. import UIKit
  23. extension HeroTransition {
  24. /**
  25. Update the progress for the interactive transition.
  26. - Parameters:
  27. - progress: the current progress, must be between 0...1
  28. */
  29. public func update(_ percentageComplete: CGFloat) {
  30. guard state == .animating else {
  31. startingProgress = percentageComplete
  32. return
  33. }
  34. self.progressRunner.stop()
  35. self.progress = Double(percentageComplete.clamp(0, 1))
  36. }
  37. /**
  38. Finish the interactive transition.
  39. Will stop the interactive transition and animate from the
  40. current state to the **end** state
  41. */
  42. public func finish(animate: Bool = true) {
  43. guard state == .animating || state == .notified || state == .starting else { return }
  44. if !animate {
  45. self.complete(finished: true)
  46. return
  47. }
  48. var maxTime: TimeInterval = 0
  49. for animator in self.animators {
  50. maxTime = max(maxTime, animator.resume(timePassed: self.progress * self.totalDuration,
  51. reverse: false))
  52. }
  53. self.complete(after: maxTime, finishing: true)
  54. }
  55. /**
  56. Cancel the interactive transition.
  57. Will stop the interactive transition and animate from the
  58. current state to the **beginning** state
  59. */
  60. public func cancel(animate: Bool = true) {
  61. guard state == .animating || state == .notified || state == .starting else { return }
  62. if !animate {
  63. self.complete(finished: false)
  64. return
  65. }
  66. var maxTime: TimeInterval = 0
  67. for animator in self.animators {
  68. var adjustedProgress = self.progress
  69. if adjustedProgress < 0 {
  70. adjustedProgress = -adjustedProgress
  71. }
  72. maxTime = max(maxTime, animator.resume(timePassed: adjustedProgress * self.totalDuration,
  73. reverse: true))
  74. }
  75. self.complete(after: maxTime, finishing: false)
  76. }
  77. /**
  78. Override modifiers during an interactive animation.
  79. For example:
  80. Hero.shared.apply([.position(x:50, y:50)], to:view)
  81. will set the view's position to 50, 50
  82. - Parameters:
  83. - modifiers: the modifiers to override
  84. - view: the view to override to
  85. */
  86. public func apply(modifiers: [HeroModifier], to view: UIView) {
  87. guard state == .animating else { return }
  88. let targetState = HeroTargetState(modifiers: modifiers)
  89. if let otherView = self.context.pairedView(for: view) {
  90. for animator in self.animators {
  91. animator.apply(state: targetState, to: otherView)
  92. }
  93. }
  94. for animator in self.animators {
  95. animator.apply(state: targetState, to: view)
  96. }
  97. }
  98. /**
  99. Override target state during an interactive animation.
  100. For example:
  101. Hero.shared.changeTarget([.position(x:50, y:50)], to:view)
  102. will animate the view's position to 50, 50 once `finish(animate:)` is called
  103. - Parameters:
  104. - modifiers: the modifiers to override
  105. - isDestination: if false, it changes the starting state
  106. - view: the view to override to
  107. */
  108. public func changeTarget(modifiers: [HeroModifier], isDestination: Bool = true, to view: UIView) {
  109. guard state == .animating else { return }
  110. let targetState = HeroTargetState(modifiers: modifiers)
  111. if let otherView = self.context.pairedView(for: view) {
  112. for animator in self.animators {
  113. animator.changeTarget(state: targetState, isDestination: !isDestination, to: otherView)
  114. }
  115. }
  116. for animator in self.animators {
  117. animator.changeTarget(state: targetState, isDestination: isDestination, to: view)
  118. }
  119. }
  120. }