├── Bubble.gif ├── BubbleTransition.swift ├── LICENSE ├── README.md └── TransitionMode.swift /Bubble.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fitomad/iOS-Bubble-Transition/9c21bcc5d4cea3b0b40583e321543b10928eb876/Bubble.gif -------------------------------------------------------------------------------- /BubbleTransition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BubbleTransition.swift 3 | // desappstre framework 4 | // 5 | // Created by Adolfo Vera Blasco on 14/03/16. 6 | // Copyright (c) 2016 Adolfo Vera Blasco. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Foundation 11 | 12 | @objc public class BubbleTransition: NSObject 13 | { 14 | /// Point in which we situate the bubble. 15 | /// By default Upper Left corner 16 | public var startingPoint: CGPoint 17 | 18 | /// The transition direction. 19 | public var transitionMode: TransitionMode 20 | 21 | /// The color of the bubble. 22 | /// Non defined? We use the presented controller background color 23 | public var bubbleColor: UIColor? 24 | 25 | /// The bubble 26 | private var bubble: UIView! 27 | /// Transition duration 28 | private var presentingDuration: Double 29 | /// Dismiss duration 30 | private var dismissDuration: Double 31 | 32 | /** 33 | Initializer 34 | */ 35 | public override init() 36 | { 37 | self.presentingDuration = 0.5 38 | self.dismissDuration = 0.35 39 | 40 | self.startingPoint = CGPointMake(0.0, 0.0) 41 | self.transitionMode = TransitionMode.Present 42 | } 43 | 44 | // 45 | // MARK: - Private Methods 46 | // 47 | 48 | /** 49 | Calculate the circle needed to cover the screen completly 50 | 51 | - Parameters: 52 | - originalSize: Size that must be covered 53 | - start: Where the bubble starts to growth 54 | */ 55 | private func frameForBubbleWithSize(originalSize: CGSize, start: CGPoint) -> CGRect 56 | { 57 | let lengthX = fmax(start.x, originalSize.width - start.x); 58 | let lengthY = fmax(start.y, originalSize.height - start.y) 59 | 60 | let offset = sqrt(lengthX * lengthX + lengthY * lengthY) * 2; 61 | 62 | return CGRectMake(0, 0, offset, offset) 63 | } 64 | } 65 | 66 | // 67 | // MARK: - UIViewControllerAnimatedTransitioning Protocol 68 | // 69 | 70 | extension BubbleTransition: UIViewControllerAnimatedTransitioning 71 | { 72 | /** 73 | Transition duration 74 | */ 75 | public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval 76 | { 77 | return self.transitionMode == .Present ? self.presentingDuration : self.dismissDuration 78 | } 79 | 80 | /** 81 | Where the magic happends :) 82 | */ 83 | public func animateTransition(transitionContext: UIViewControllerContextTransitioning) 84 | { 85 | guard let 86 | containerView = transitionContext.containerView(), 87 | toView = transitionContext.viewForKey(UITransitionContextToViewKey), 88 | fromView = transitionContext.viewForKey(UITransitionContextFromViewKey) 89 | else 90 | { 91 | return 92 | } 93 | 94 | if transitionMode == TransitionMode.Present 95 | { 96 | let originalCenter = toView.center 97 | let originalSize = toView.frame.size 98 | 99 | let frame: CGRect = self.frameForBubbleWithSize(originalSize, start: self.startingPoint) 100 | 101 | self.bubble = UIView(frame: frame) 102 | self.bubble.layer.cornerRadius = CGRectGetHeight(self.bubble.frame) / 2 103 | self.bubble.center = self.startingPoint 104 | self.bubble.transform = CGAffineTransformMakeScale(0.001, 0.001) 105 | 106 | if let bubbleColor = self.bubbleColor 107 | { 108 | self.bubble.backgroundColor = bubbleColor 109 | } 110 | else 111 | { 112 | self.bubble.backgroundColor = toView.backgroundColor 113 | } 114 | 115 | toView.center = startingPoint 116 | toView.transform = CGAffineTransformMakeScale(0.001, 0.001) 117 | toView.alpha = 0 118 | 119 | containerView.addSubview(toView) 120 | containerView.addSubview(self.bubble) 121 | 122 | UIView.animateWithDuration(self.presentingDuration, 123 | animations: 124 | { 125 | self.bubble.transform = CGAffineTransformIdentity 126 | 127 | toView.transform = CGAffineTransformIdentity 128 | toView.alpha = 1 129 | toView.center = originalCenter 130 | }, 131 | completion: { (finished: Bool) -> (Void) in 132 | if finished 133 | { 134 | self.bubble.removeFromSuperview() 135 | 136 | transitionContext.completeTransition(true) 137 | } 138 | } 139 | ) 140 | } 141 | else 142 | { 143 | let originalSize = fromView.frame.size 144 | 145 | self.bubble.frame = self.frameForBubbleWithSize(originalSize, start: startingPoint) 146 | self.bubble.layer.cornerRadius = CGRectGetHeight(self.bubble.frame) / 2 147 | self.bubble.center = self.startingPoint 148 | 149 | containerView.addSubview(toView) 150 | containerView.addSubview(self.bubble) 151 | 152 | UIView.animateWithDuration(self.dismissDuration, 153 | animations: 154 | { 155 | self.bubble.transform = CGAffineTransformMakeScale(0.001, 0.001) 156 | }, 157 | completion: { (finished: Bool) -> (Void) in 158 | if finished 159 | { 160 | toView.removeFromSuperview() 161 | self.bubble.removeFromSuperview() 162 | 163 | transitionContext.completeTransition(true) 164 | } 165 | } 166 | ) 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Adolfo 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iOS Bubble Transition 2 | Transition between controllers coding in Swift. The transition starts at... better take a look below. 3 | 4 | ![Bubble Transition](https://github.com/fitomad/iOS-Bubble-Transition/blob/master/Bubble.gif?raw=true) 5 | 6 | ## Code 7 | You only need two files: 8 | 9 | - `BubbleTransition.swift` 10 | - `TransitionMode.swift` 11 | 12 | ## Example 13 | Here It is `BubbleTransition` in action 14 | 15 | ```swift 16 | let bubble: BubbleTransition = BubbleTransition() 17 | 18 | bubble.startingPoint = someButtonYouTap.center 19 | bubble.transitionMode = TransitionMode.Present 20 | // The background color for bubble. 21 | // If not define the transition takes the 22 | // presented controller background color 23 | bubble.bubbleColor = UIColor.blueColor() 24 | ``` 25 | 26 | ## Contact 27 | Questions? You can find me on **twitter** [@fitomad](https://twitter.com/fitomad) 28 | -------------------------------------------------------------------------------- /TransitionMode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransitionMode.swift 3 | // desappstre framework 4 | // 5 | // Created by Adolfo Vera Blasco on 14/03/16. 6 | // Copyright (c) 2016 Adolfo Vera Blasco. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | The possible directions of the transition. 13 | 14 | - Present: For presenting a new controller 15 | - Dismiss: For dismissing the current controller 16 | */ 17 | @objc public enum TransitionMode: Int 18 | { 19 | case Present 20 | case Dismiss 21 | } 22 | --------------------------------------------------------------------------------