Gradually adding rectangle animation in iOS - ios

I have a single view application in Xcode and doing the following in ViewController.swift. My objective is to have the screen filled up with a brown colored rectangle gradually over 5 seconds. Am I missing something or is the approach completely wrong?
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let expandAnimation: CABasicAnimation = CABasicAnimation(keyPath: "path")
expandAnimation.fromValue = UIBezierPath(rect: CGRect(x: 0.0, y: 0.0, width: 0.0, height: 0.0))
expandAnimation.toValue = UIBezierPath(rect: CGRect(x: 0.0, y: 0.0, width: self.view.bounds.size.width, height: self.view.bounds.size.height))
expandAnimation.duration = 5.0
expandAnimation.fillMode = kCAFillModeForwards
expandAnimation.isRemovedOnCompletion = false
let rectLayer: CAShapeLayer = CAShapeLayer()
rectLayer.fillColor = UIColor.brown.cgColor
rectLayer.path = UIBezierPath(rect: CGRect(x: 0.0, y: 0.0, width: 0.0, height: 0.0)).cgPath
rectLayer.add(expandAnimation, forKey: nil)
self.view.layer.addSublayer(rectLayer)
}
I don't want the color to gradually appear. I want a glass filling kind of effect. Imagine this
except for the fancy wavy effects.

After understanding your question better, you want to simulate the filing of a water glass (without the animation of the wave), you can achieve that through:
let myLayer: CALayer = .init()
myLayer.backgroundColor = UIColor.red.cgColor
self.view.layer.addSublayer(myLayer)
func animateFilling(to view:UIView)
{
var mFrame = CGRect(x: 0, y: view.frame.size.height, width: view.frame.size.width, height: 0)
myLayer.frame = mFrame
let fillingAnim = CABasicAnimation(keyPath: "bounds")
fillingAnim.fillMode = kCAFillModeForwards
fillingAnim.fromValue = mFrame
fillingAnim.duration = 2
fillingAnim.isRemovedOnCompletion = false
mFrame.size.height = 1000
fillingAnim.toValue = mFrame
myLayer.add(fillingAnim, forKey: nil)
}

I think it's easy to do it like that if you don't want top wave
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let vv = UIView(frame: CGRect(x: 0, y: self.view.bounds.size.height, width: self.view.bounds.size.width, height: 0))
vv.backgroundColor = UIColor.brown
self.view.addSubview(vv)
UIView.animate(withDuration: 5.0) {
vv.frame = CGRect(x: 0, y: self.view.bounds.size.height / 3.0, width: self.view.bounds.size.width, height: self.view.bounds.size.height * 2 / 3.0)
}
}

Related

how to programmatically show a colored disk behind a UIImageView, in swift on an iOS device

I have an icon that I programmatically display.
How can I display a solid, colored disk behind the icon, at the same screen position?
Icon is opaque.
I will sometimes programmatically change screen position and disk's diameter and color.
Here's how I programmatically display the icon now.............
DispatchQueue.main.async
{
ViewController.wrist_band_UIImageView.frame = CGRect( x: screen_position_x,
y: screen_position_y,
width: App_class.screen_width,
height: App_class.screen_height)
}
UPDATE #1 for D.Mika below...
UPDATE #2 for D.Mika below...
import UIKit
import Foundation
class ViewController: UIViewController
{
static var circleView: UIView!
static let wrist_band_UIImageView: UIImageView = {
let theImageView = UIImageView()
theImageView.image = UIImage( systemName: "applewatch" )
theImageView.translatesAutoresizingMaskIntoConstraints = false
return theImageView
}()
override func viewDidLoad()
{
super.viewDidLoad()
view.addSubview( ViewController.wrist_band_UIImageView )
// Init disk image:
ViewController.circleView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0))
ViewController.circleView.backgroundColor = .red
ViewController.circleView.layer.cornerRadius = view.bounds.size.height / 2.0
ViewController.circleView.clipsToBounds = true
// Add view to view hierarchy below image view
ViewController.circleView.insertSubview(view, belowSubview: ViewController.wrist_band_UIImageView)
App_class.display_single_wearable()
}
}
class App_class
{
static var is_communication_established = false
static var total_packets = 0
static func display_single_wearable()
{
ViewController.wrist_band_UIImageView.frame = CGRect(x: 0, y: 0,
width: 100, height: 100)
ViewController.circleView.frame = CGRect( x: 0,
y: 0,
width: 100,
height: 100)
ViewController.circleView.layer.cornerRadius = 100
}
static func process_location_xy(text_location_xyz: String)
{}
} // App_class
You can display a colored circle using the following view:
circleView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 100.0, height: 100.0))
circleView.backgroundColor = .red
circleView.layer.cornerRadius = view.bounds.size.height / 2.0
circleView.clipsToBounds = true
// Add view to view hierarchy below image view
view.insertSubview(circleView, belowSubview: wrist_band_UIImageView)
You can change it's position and size by applying a new frame. But you have to change the layer's cornerRadius accordingly.
This is a simple example in a playground:
Edit:
I've modified the sample code to add the view the view hierarchy.
BUT, you still need to adjust the circle's frame, when you modify the image view's frame. (and the cornerRadius accordingly). For example
DispatchQueue.main.async
{
ViewController.wrist_band_UIImageView.frame = CGRect( x: screen_position_x,
y: screen_position_y,
width: App_class.screen_width,
height: App_class.screen_height)
circleView.frame = CGRect( x: screen_position_x,
y: screen_position_y,
width: App_class.screen_width,
height: App_class.screen_height)
circleView.layer.cornerRadius = App_class.screen_width
}
And you need to add a variable to the viewController holding the reference to the circle view, like:
var circleView: UIView!
The following answer works.
The answers from d.mika above did not work. Plus, he was insulting. ;-)
// Show red circle
let circlePath = UIBezierPath(arcCenter: CGPoint(x: 200, y: 400), radius: CGFloat(40), startAngle: CGFloat(0), endAngle: CGFloat(Double.pi * 2), clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
// Change the fill color
shapeLayer.fillColor = UIColor.red.cgColor
// You can change the stroke color
shapeLayer.strokeColor = UIColor.red.cgColor
// You can change the line width
shapeLayer.lineWidth = 3.0
view.layer.addSublayer(shapeLayer)

What is the proper way to scale a view while animating it with CAKeyframeAnimation and BezierPath

The following code effectively animates and scales a view along a BezierPath but I feel like I'm cheating since I'm mixing UIKit and CAKeyframeAnimation (Core Animation) animations.
Is there a better way to scale a view while animating it along the BezierPath?
func animateIt(){
let myView = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
myView.backgroundColor = .blue
myView.layer.cornerRadius = myView.frame.height / 2
view.addSubview(myView)
let startPoint = CGPoint(x: 250, y: 500)
let apexPoint = CGPoint(x: 100, y: 50)
let endPoint = CGPoint(x: 50, y: 350)
let durationTime = 1.5
let path = UIBezierPath()
path.move(to: startPoint)
path.addQuadCurve(to: endPoint, controlPoint: apexPoint)
let animation = CAKeyframeAnimation(keyPath: "position")
animation.path = path.cgPath
animation.duration = durationTime
myView.layer.add(animation, forKey: "bezier")
myView.center = endPoint
UIView.animate(withDuration: durationTime, animations: {
myView.transform = CGAffineTransform(scaleX: 0.5, y: 0.5);
})
}
I tried using a second CAKeyframeAnimation animation instead of the UIKit animation and used the array of key values but no matter what I do, I cannot get a uniform scale, it scales at the beginning but not at the end.
let scaleAnimation = CAKeyframeAnimation(keyPath: "scale")
scaleAnimation.values = [1.0, 0.9, 0.5,]
myView.layer.add(scaleAnimation, forKey: "scale")
Thanks!

Touch event on Visible Portion of Views ios swift 4

I am working of Photo Collage which is in Swift4 , I had created collage using UIBezierPath as Below
I have 5 scroll views in Storyboard and the sequence of Scrollviews as Below
Using Following code I am creating Shapes :
var path1 = UIBezierPath()
path1.move(to: CGPoint(x: 0, y: 0))
path1.addLine(to: CGPoint(x: superView.frame.width / 2, y: 0))
path1.addLine(to: CGPoint(x: 0, y: superView.frame.width / 2))
path1.addLine(to: CGPoint(x: 0, y: 0))
var borderPathRef1 = path1.cgPath
var borderShapeLayer1 = CAShapeLayer()
borderShapeLayer1.path = borderPathRef1
scroll1.layer.mask = borderShapeLayer1
scroll1.layer.masksToBounds = true
var path2 = UIBezierPath()
path2.move(to: CGPoint(x: 0, y: 0))
path2.addLine(to: CGPoint(x: superView.frame.width / 2, y: 0))
path2.addLine(to: CGPoint(x: superView.frame.width / 2, y: superView.frame.width / 2))
path2.addLine(to: CGPoint(x: 0, y: 0))
var borderPathRef2 = path2.cgPath
var borderShapeLayer2 = CAShapeLayer()
borderShapeLayer2.path = borderPathRef2
scroll2.layer.mask = borderShapeLayer2
scroll2.layer.masksToBounds = true
Now the issue is I am not able to get touch event of Scrollviews as Scroll5 is on top. I want to get Touch on Overlapped views like Scroll1, Scroll2 and so on. In Short I need touch event for particular view on the portion of area where the view is visible.
See The Image Below Where I want Touch for Views.
How can I get touch on Overlapped Views?
Please Help!
You have to be sure that you set the superView of scrollview to isUserInterfaceEnabled=true first.
To get overlapped views touch event:
here is my code:
class CustomView: UIView {
let view1: UIView
let view2: UIView
let view3: UIView
let view4: UIView
let view5: UIView
override init(frame: CGRect) {
view1 = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
view1.backgroundColor = UIColor.black
view1.isUserInteractionEnabled = true
view2 = UIView(frame: CGRect(x: 100, y: 0, width: 100, height: 100))
view2.backgroundColor = UIColor.orange
view2.isUserInteractionEnabled = true
view3 = UIView(frame: CGRect(x: 0, y: 100, width: 100, height: 100))
view3.backgroundColor = UIColor.blue
view3.isUserInteractionEnabled = true
view4 = UIView(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
view4.backgroundColor = UIColor.brown
view4.isUserInteractionEnabled = true
view5 = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
view5.tag = 121
view5.backgroundColor = UIColor.red
super.init(frame: frame)
self.addSubview(view1)
self.addSubview(view2)
self.addSubview(view3)
self.addSubview(view4)
self.addSubview(view5)
view1.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(touchAction)))
}
#objc func touchAction () {
print("----------- touch view 1")
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if (view1.point(inside: self.convert(point, to: view1), with: event)) {
return view1
}
return self
}
}
The function hitTest decides that which view you are touching, so you just need to return the overlapped view.

Adding inner shadow to top of UIView

I looked up but I couldn't find how I can add an inner shadow to UIView, only top (from top to bottom) for Swift. What is the best way add inner circle in Swift?
Edit: I've found some questions & answers on SO however they are either in obj-c or looks so complicated. I was just looking for a more Swifty way, if there is any
What I want to achieve:
Here's a pure Swift version that I whipped up:
public class EdgeShadowLayer: CAGradientLayer {
public enum Edge {
case Top
case Left
case Bottom
case Right
}
public init(forView view: UIView,
edge: Edge = Edge.Top,
shadowRadius radius: CGFloat = 20.0,
toColor: UIColor = UIColor.white,
fromColor: UIColor = UIColor.black) {
super.init()
self.colors = [fromColor.cgColor, toColor.cgColor]
self.shadowRadius = radius
let viewFrame = view.frame
switch edge {
case .Top:
startPoint = CGPoint(x: 0.5, y: 0.0)
endPoint = CGPoint(x: 0.5, y: 1.0)
self.frame = CGRect(x: 0.0, y: 0.0, width: viewFrame.width, height: shadowRadius)
case .Bottom:
startPoint = CGPoint(x: 0.5, y: 1.0)
endPoint = CGPoint(x: 0.5, y: 0.0)
self.frame = CGRect(x: 0.0, y: viewFrame.height - shadowRadius, width: viewFrame.width, height: shadowRadius)
case .Left:
startPoint = CGPoint(x: 0.0, y: 0.5)
endPoint = CGPoint(x: 1.0, y: 0.5)
self.frame = CGRect(x: 0.0, y: 0.0, width: shadowRadius, height: viewFrame.height)
case .Right:
startPoint = CGPoint(x: 1.0, y: 0.5)
endPoint = CGPoint(x: 0.0, y: 0.5)
self.frame = CGRect(x: viewFrame.width - shadowRadius, y: 0.0, width: shadowRadius, height: viewFrame.height)
}
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
To use it,
let topShadow = EdgeShadowLayer(forView: targetView, edge: .Top)
targetView.layer.addSublayer(topShadow)
Note that it defaults to a black-to-white gradient that's 20 points deep.
The full code, with a sample UIViewController that lets you toggle shadows on all four corners of a view, can be found at https://github.com/jrtibbetts/Tenebrae. I've also documented the EdgeShadowLayer pretty thoroughly.
I used implement inner shadow to UIView using Objective-C. I try to translate code into swift. Please forgive me for my poor swift syntax
you can call function below in UIView.didMoveToSuperview
func drawShadow() {
if nil == self.shadowLayer {
let size = self.frame.size
self.clipsToBounds = true
let layer: CALayer = CALayer()
layer.backgroundColor = UIColor.lightGrayColor().CGColor
layer.position = CGPointMake(size.width / 2, -size.height / 2 + 0.5)
layer.bounds = CGRectMake(0, 0, size.width, size.height)
layer.shadowColor = UIColor.darkGrayColor().CGColor
layer.shadowOffset = CGSizeMake(0.5, 0.5)
layer.shadowOpacity = 0.8
layer.shadowRadius = 5.0
self.shadowLayer = layer
self.layer.addSublayer(layer)
}
}
I tweaked the modification made by #anoop4real using clear as the toColor and made the interface more in-line with the shadow settings in CALayer, including defaults, with the exception of opacity, which is set to 0.0 by default. I went with a default of 0.6 since it looked the most natural.
extension UIView {
func addShadow(to edges: [UIRectEdge], radius: CGFloat = 3.0, opacity: Float = 0.6, color: CGColor = UIColor.black.cgColor) {
let fromColor = color
let toColor = UIColor.clear.cgColor
let viewFrame = self.frame
for edge in edges {
let gradientLayer = CAGradientLayer()
gradientLayer.colors = [fromColor, toColor]
gradientLayer.opacity = opacity
switch edge {
case .top:
gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)
gradientLayer.frame = CGRect(x: 0.0, y: 0.0, width: viewFrame.width, height: radius)
case .bottom:
gradientLayer.startPoint = CGPoint(x: 0.5, y: 1.0)
gradientLayer.endPoint = CGPoint(x: 0.5, y: 0.0)
gradientLayer.frame = CGRect(x: 0.0, y: viewFrame.height - radius, width: viewFrame.width, height: radius)
case .left:
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
gradientLayer.frame = CGRect(x: 0.0, y: 0.0, width: radius, height: viewFrame.height)
case .right:
gradientLayer.startPoint = CGPoint(x: 1.0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 0.0, y: 0.5)
gradientLayer.frame = CGRect(x: viewFrame.width - radius, y: 0.0, width: radius, height: viewFrame.height)
default:
break
}
self.layer.addSublayer(gradientLayer)
}
}
func removeAllShadows() {
if let sublayers = self.layer.sublayers, !sublayers.isEmpty {
for sublayer in sublayers {
sublayer.removeFromSuperlayer()
}
}
}
}
The top view is the default settings, and the bottom uses a radius of 5.0 to show more clearly.
view1.addShadow([.top, .bottom, .left, .right])
view2.addShadow([.top, .bottom, .left, .right], radius: 5.0)
view2.backgroundColor = .orange
I updated #NRitH's answer and made an extension out of it also modified so that you can manipulate multiple edges in one go
usage
myview.addShadow(to: [.top,.bottom], radius: 15.0)
extension UIView{
func addShadow(to edges:[UIRectEdge], radius:CGFloat){
let toColor = UIColor(colorLiteralRed: 235.0/255.0, green: 235.0/255.0, blue: 235.0/255.0, alpha: 1.0)
let fromColor = UIColor(colorLiteralRed: 188.0/255.0, green: 188.0/255.0, blue: 188.0/255.0, alpha: 1.0)
// Set up its frame.
let viewFrame = self.frame
for edge in edges{
let gradientlayer = CAGradientLayer()
gradientlayer.colors = [fromColor.cgColor,toColor.cgColor]
gradientlayer.shadowRadius = radius
switch edge {
case UIRectEdge.top:
gradientlayer.startPoint = CGPoint(x: 0.5, y: 0.0)
gradientlayer.endPoint = CGPoint(x: 0.5, y: 1.0)
gradientlayer.frame = CGRect(x: 0.0, y: 0.0, width: viewFrame.width, height: gradientlayer.shadowRadius)
case UIRectEdge.bottom:
gradientlayer.startPoint = CGPoint(x: 0.5, y: 1.0)
gradientlayer.endPoint = CGPoint(x: 0.5, y: 0.0)
gradientlayer.frame = CGRect(x: 0.0, y: viewFrame.height - gradientlayer.shadowRadius, width: viewFrame.width, height: gradientlayer.shadowRadius)
case UIRectEdge.left:
gradientlayer.startPoint = CGPoint(x: 0.0, y: 0.5)
gradientlayer.endPoint = CGPoint(x: 1.0, y: 0.5)
gradientlayer.frame = CGRect(x: 0.0, y: 0.0, width: gradientlayer.shadowRadius, height: viewFrame.height)
case UIRectEdge.right:
gradientlayer.startPoint = CGPoint(x: 1.0, y: 0.5)
gradientlayer.endPoint = CGPoint(x: 0.0, y: 0.5)
gradientlayer.frame = CGRect(x: viewFrame.width - gradientlayer.shadowRadius, y: 0.0, width: gradientlayer.shadowRadius, height: viewFrame.height)
default:
break
}
self.layer.addSublayer(gradientlayer)
}
}
func removeAllSublayers(){
if let sublayers = self.layer.sublayers, !sublayers.isEmpty{
for sublayer in sublayers{
sublayer.removeFromSuperlayer()
}
}
}
}
Swift 5 extension
extension UIView {
func addInnerShadow() {
let innerShadow = CALayer()
innerShadow.frame = bounds
// Shadow path (1pt ring around bounds)
let radius = self.layer.cornerRadius
let path = UIBezierPath(roundedRect: innerShadow.bounds.insetBy(dx: 2, dy:2), cornerRadius:radius)
let cutout = UIBezierPath(roundedRect: innerShadow.bounds, cornerRadius:radius).reversing()
path.append(cutout)
innerShadow.shadowPath = path.cgPath
innerShadow.masksToBounds = true
// Shadow properties
innerShadow.shadowColor = UIColor.black.cgColor
innerShadow.shadowOffset = CGSize(width: 0, height: 0)
innerShadow.shadowOpacity = 0.5
innerShadow.shadowRadius = 2
innerShadow.cornerRadius = self.layer.cornerRadius
layer.addSublayer(innerShadow)
}
}
I rewrote #NRitH solution on Swift 3, also slightly refactor it:
final class SideShadowLayer: CAGradientLayer {
enum Side {
case top,
bottom,
left,
right
}
init(frame: CGRect, side: Side, shadowWidth: CGFloat,
fromColor: UIColor = .black,
toColor: UIColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0),
opacity: Float = 0.5) {
super.init()
colors = [fromColor.cgColor, toColor.cgColor]
self.opacity = opacity
switch side {
case .bottom:
startPoint = CGPoint(x: 0.5, y: 1.0)
endPoint = CGPoint(x: 0.5, y: 0.0)
self.frame = CGRect(x: 0, y: frame.height - shadowWidth, width: frame.width, height: shadowWidth)
case .top:
startPoint = CGPoint(x: 0.5, y: 0.0)
endPoint = CGPoint(x: 0.5, y: 1.0)
self.frame = CGRect(x: 0, y: 0, width: frame.width, height: shadowWidth)
case .left:
startPoint = CGPoint(x: 0.0, y: 0.5)
endPoint = CGPoint(x: 1.0, y: 0.5)
self.frame = CGRect(x: 0, y: 0, width: shadowWidth, height: frame.height)
case .right:
startPoint = CGPoint(x: 1.0, y: 0.5)
endPoint = CGPoint(x: 0.0, y: 0.5)
self.frame = CGRect(x: frame.width - shadowWidth, y: 0, width: shadowWidth, height: frame.height)
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
If you don't mind using clipsToBounds = true, you can create a new CALayer offset just off the edge of your view and add the shadow to THAT view. This is what J.Hunter's answer does.
J.Hunter's code adds a top shadow, here I updated it to Swift 5 and added it to the bottom.
Swift 5:
override func draw(_ rect: CGRect) {
// Create Inner Shadow. Not sure about efficiency of this.
// You may want to create a shadowLayer property
// and only run this code if it hasn't been created yet.
let size = rect.size
clipsToBounds = true // Don't want to see your fake view layer
let innerShadowLayer: CALayer = CALayer()
// Need to set a backgroundColor or it doesn't work
innerShadowLayer.backgroundColor = UIColor.black.cgColor
// Position your shadow layer (anchor point is in the center)
// on the edge of where your shadow needs to be.
// In my case this moves the shadow layer to the
// bottom edge of my view
innerShadowLayer.position = CGPoint(x: size.width / 2, y: size.height + (size.height / 2))
// This could be smaller I think, just copying J.Hunter's code...
innerShadowLayer.bounds = CGRect(x: 0, y: 0, width: size.width, height: size.height)
// Normal shadow layer properties you'd use for an outer shadow
innerShadowLayer.shadowColor = UIColor.black.cgColor
innerShadowLayer.shadowOffset = CGSize(width: 0, height: 0)
innerShadowLayer.shadowOpacity = 0.3
innerShadowLayer.shadowRadius = 3
layer.addSublayer(innerShadowLayer)
}

Circular transition (mask) in iOS and Objective C

We were wondering how we can easily build a circular mask, that blends out the background and transitions into a new view, with new buttons? See example here (watch the red planet gets triggered):
//Swift 4
This is a simple static method for circular bubble transition from a point screen.
//as shown on this link
https://github.com/andreamazz/BubbleTransition
import UIKit
class AnimationUtility: UIViewController {
static func animateBubbleTrnsitionView( selfView: UIView, point : CGPoint) {
//let button = CGRect.init(x: 30, y: selfView.frame.size.height - 15, width: 45, height: 45)
let button = CGRect.init(x: point.x, y: point.y, width: 0, height: 0)
let circleMaskPathInitial = UIBezierPath(ovalIn: CGRect.init(x: point.x, y: point.y, width: 1, height: 1))
let extremePoint = CGPoint(x: point.x, y: 15 - selfView.frame.size.height - 200)
let radius = sqrt((extremePoint.x*extremePoint.x) + (extremePoint.y*extremePoint.y))
let circleMaskPathFinal = UIBezierPath(ovalIn: (button.insetBy(dx: -radius, dy: -radius)))
let maskLayer = CAShapeLayer()
maskLayer.path = circleMaskPathFinal.cgPath
selfView.layer.mask = maskLayer
let maskLayerAnimation = CABasicAnimation(keyPath: "path")
maskLayerAnimation.fromValue = circleMaskPathInitial.cgPath
maskLayerAnimation.toValue = circleMaskPathFinal.cgPath
maskLayerAnimation.duration = 0.9
maskLayer.add(maskLayerAnimation, forKey: "path")
}
}
Use this code in following way
Perform segue or push without animation.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
switch segue.identifier! {
case "navToHomeWithoutanimation":
self.navigationController?.view.backgroundColor = APP_ORANGE_COLOR //which ever color you want
let vc = segue.destination as! MapViewController
AnimationUtility.animateBubbleTrnsitionView(selfView: vc.view, point: self.view.center)
break
}
}
//The animation will start to animate from given point.
Swift code :
I writted all code appdelegate file. Used a screenshot of timeline rather than a full-blown UITableView.
First, let’s add the screenshot on the window:
let imageView = UIImageView(frame: self.window!.frame)
imageView.image = UIImage(named: "twitterscreen")
self.window!.addSubview(imageView)
self.mask = CALayer()
self.mask!.contents = UIImage(named: "twitter logo mask").CGImage
self.mask!.bounds = CGRect(x: 0, y: 0, width: 100, height: 100)
self.mask!.anchorPoint = CGPoint(x: 0.5, y: 0.5)
self.mask!.position = CGPoint(x: imageView.frame.size.width/2, y: imageView.frame.size.height/2)
imageView.layer.mask = mask
animating the mask. You’ll observe that the bird reduces in size for a bit, and then increases in size, so to do that using just one animation, let’s use CAKeyframeAnimation.
let keyFrameAnimation = CAKeyframeAnimation(keyPath: "bounds")
keyFrameAnimation.duration = 1
keyFrameAnimation.timingFunctions = [CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut), CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)]
let initalBounds = NSValue(CGRect: mask!.bounds)
let secondBounds = NSValue(CGRect: CGRect(x: 0, y: 0, width: 90, height: 90))
let finalBounds = NSValue(CGRect: CGRect(x: 0, y: 0, width: 1500, height: 1500))
keyFrameAnimation.values = [initalBounds, secondBounds, finalBounds]
keyFrameAnimation.keyTimes = [0, 0.3, 1]
self.mask!.addAnimation(keyFrameAnimation, forKey: "bounds")
If you see result please visit the github repo. https://github.com/rounak/TwitterBirdAnimation/

Resources