Hallo vrienden, Leo Hier. Today’s topic is how to use Convert Function in Swift to create animations.

Today we will see how can you a cool animation using scale and translate in your projects. Knowing how to animate things gives life and vibrancy to your projects. Custom animations can be really hard and not intuitive if you are dealing with Transition Animations. But when you have to do simple animations that don’t include multiple ViewControllers everything tends to be easier.

Let’s code! But first…

 

Painting of The Day

This painting is called “Ballet With Magic” by Leonid Afremov. He was born on 12 July 1955 in Vitebsk, Belarus – Died on August 19th, 2019, in Playa Del Carmen, Quintana Roo, Mexico. Russian–Israeli modern impressionistic artist who works mainly with a palette knife and oils. He developed his own unique technique and style which is unmistakable and cannot be confused with other artists.

Afremov is mainly known as being a self-representing artist who promotes and sells his work exclusively over the internet with very few exhibitions and involvement from dealers and galleries.

I choose this painter because his painting style and color are so vivid, looks like it’s animated. He died last year.

 

The Problem – How to Use Convert Function in Swift

Imagine that you have a screen that has a trash bin. When the user taps in another view it should do a moving while scale down animation to the trash bin and vanishes.

The final result should be this (without the right star):

Let’s start the setup of the UIKit animation by positioning our UIViews on the screen.

 

Layout Setup

First, create a new project with a storyboard and copy this to the ViewController class scope :

class ViewController: UIViewController {
    var trashBinImageView = UIImageView(image: UIImage(systemName: "trash"))
    var scrollView = UIScrollView()
    var starImageViewOut = UIImageView(image: UIImage(systemName: "star"))
    var isImageViewMoved = false
    var imageViewOutCenter: CGPoint?
}

As you can imagine this would be the trash bin from the gif and the star. I set the scroll view just to add a layer of complexity and another target coordinate system for our star view. Talking about the starImageViewOut the Out part is because this view is out of the target coordinate system, this means that you have to do some conversion to know where the target object is.

Now let’s setup the viewDidLoad:

override func viewDidLoad() {
    super.viewDidLoad()
    scrollView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(scrollView)
    
    NSLayoutConstraint.activate([
        scrollView.topAnchor.constraint(equalTo: view.topAnchor),
        scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -200),
        scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30),
        scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
    ])
    
    scrollView.isUserInteractionEnabled = true
    scrollView.bounces = true
    scrollView.alwaysBounceVertical = true
    scrollView.alwaysBounceHorizontal = true
    
    trashBinImageView.translatesAutoresizingMaskIntoConstraints = false
    scrollView.addSubview(trashBinImageView)
    
    NSLayoutConstraint.activate([
        trashBinImageView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: CGFloat(250)),
        trashBinImageView.topAnchor.constraint(equalTo: scrollView.topAnchor),
        trashBinImageView.heightAnchor.constraint(equalToConstant: 100),
        trashBinImageView.widthAnchor.constraint(equalToConstant: 100)
    ])
    
    view.addSubview(starImageViewOut)
    starImageViewOut.translatesAutoresizingMaskIntoConstraints = false
    
    starImageViewOut.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(didTapStar))) // add the tap gesture to the UIImageView
    starImageViewOut.isUserInteractionEnabled = true
    
    NSLayoutConstraint.activate([
        starImageViewOut.leadingAnchor.constraint(equalTo: view.leadingAnchor),
        starImageViewOut.bottomAnchor.constraint(equalTo: view.bottomAnchor),
        starImageViewOut.heightAnchor.constraint(equalToConstant: 100),
        starImageViewOut.widthAnchor.constraint(equalToConstant: 100)
    ])
}

This is just regular layout stuff. You can notice that the scroll view has leading padding to turn things more interesting. This padding is important to show how can we find a view in other coordinates systems.

 

UITapGestureRecognizer Setup

Now it’s time to set up the animation when the user taps on the star.

@objc private func didTapStar() { // Mark 1
    UIView.animate(withDuration: 1) { [self] in // Mark 2
        if !isImageViewMoved {
            
            let transform = starImageViewOut.transform
            let trashBinConvertedFrame = view.convert(trashBinImageView.center, from: scrollView) // Mark 3
            //let trashBinConcertedFrame2 = scrollView.convert(trashBinImageView.center, to: view) // Mark 3 this is the same result as above, choose whatever you want
            print("Trash Bin Converted CGPoints:", trashBinConvertedFrame, trashBinConcertedFrame2) // Mark 4
            print("Trash Bin Original CGPoint:", trashBinImageView.center) // Mark 4
            
            let scaleTransform = transform.scaledBy(x: 0.1, y: 0.1) // Mark 5
            starImageViewOut.transform = scaleTransform
            starImageViewOut.center = trashBinConvertedFrame
            starImageViewOut.alpha = 0.1 // Mark 6
            isImageViewMoved = true // Mark 7
        } else {
            starImageViewOut.transform = .identity
            starImageViewOut.center = imageViewOutCenter ?? CGPoint(x: 50, y: 50) // Mark 8
            starImageViewOut.alpha = 1
            isImageViewMoved = false
        }
    }
}

Let’s discover what exactly this code does:

  1. Mark 1 – This function is used by a selector so it has to be annotated with @objc
  2. Mark 2 – This will start the animation block. Nothing fancy here but always remember that animation blocks are asynchronous code.
  3. Mark 3 – This is the famous convert function. It converts a CGPoint or a frame from one coordinate system to another coordinate system. Each view in swift has its own coordinate system, therefore when you try to find the position of a view in another coordinate system, you can use the convert function. In our example, the trash bin is in UIScrollView coordinate system but the StarImageViewOut is in the ViewController.view coordinate system. You can use the convert(_,to:) and the convert(_,from:) that the result is the same, you will only need to change the parameters and the caller.
  4. Mark 4 – This print shows the difference between getting the center property from the view itself and the center from the convert function.
  5. Mark 5 – We are going to scale to 1/10 of the original size to give the user the impression of a vanishing item.
  6. Mark 6 – We are also reducing the alpha to 0.1 just to be able to tap it again to return to the original state. If you set alpha = 0 this disables the UIImageView tap capabilities.
  7. Mark 7 – Here is the logic if you want to tap again to restore the original position.
  8. Mark 8 – Just setting the center to the original place.

Now to finish the code we have to set the center to the original place:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    imageViewOutCenter = starImageViewOut.center
}

We will make sure that the trash bin center property is already drawn and correctly set on the screen to get the value.

And that’s it!

 

Code Result

And you should see in the logs something like this:

The original CGPoint gives 300 for X value and 49 to the Y value and this is correct. This is correct inside the UIScrollView coordinate system, this means that if you want to find inside the UIScrollView the trash bin image view center you should use those values. But… the star isn’t inside the scroll view so that’s why we have to use the `convert` method to find where exactly set the new center for the star image view.

Looking at the image above you can see that the X value from the converted system has 30 more points and the Y value has 50 more points. The X value is because of scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30) this line. As the scroll view starts 30 points to the view’s leading anchor, the X is 300 + 30. And the Y value is because you have top safe margins that you have to take into account to position the new view.

That’s it!

 

Summary – How to Use Convert Function in Swift

Today we learn how to use convert function and how it can be handy to do cool animations with different coordinate systems. Now you can amaze your customers with very nice animations and bring life to your applications.

That’s all my people, I hope you liked reading this article as much as I enjoyed writing it. If you want to support this blog you can Buy Me a Coffee or leave a comment saying hello. You can also sponsor posts and I’m open to freelance writing! You can reach me on LinkedIn or Twitter and send me an e-mail through the contact page.

Thanks for reading and… That’s all folks.

Credits:

title image