Shared Element Transition with Hero Library in iOS Swift
In this article, we will explore how to implement a shared element transition between two view controllers in an iOS app using the Hero Library. We’ll dive into the basics of shared element transitions, the Hero Library, and provide step-by-step instructions on how to achieve this effect.
What is a Shared Element Transition?
A shared element transition is a type of animation where a view controller presents a new view controller while maintaining the visual state of the previous view controller. This can include elements such as text, images, or even entire sections of the screen. The goal of shared element transitions is to create an intuitive and immersive user experience.
What is Hero Library?
Hero Library is an open-source library for managing hero animations in iOS apps. It provides a simple and elegant way to add animations to your app’s navigation between view controllers. With Hero Library, you can customize the animation type, duration, and even add custom transitions.
Setting Up Hero Library
Before we dive into implementing shared element transitions, let’s set up Hero Library in our project. To do this, we’ll need to install the library using CocoaPods or by adding it directly to our project.
# Install Hero Library using CocoaPods
pod 'Hero'
After installing Hero Library, we need to import it into our ViewController and enable hero animations for our UINavigationController.
Enabling Hero Animations
To enable hero animations, we need to add the following line of code:
navigationController?.hero.isEnabled = true
This will enable hero animations for all view controllers that are part of the UINavigationController. We can also customize the animation type and duration by using different classes provided by the Hero Library.
Implementing Shared Element Transition
Now that we have Hero Library set up, let’s implement a shared element transition between our table view controller and detail view controller.
Table View Controller
First, let’s modify our table view controller to present the detail view controller with a shared element transition.
import UIKit
class TableViewController: UIViewController {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Get the image URL from the selected row
guard let imageUrl = images[indexPath.row] else { return }
// Create a hero configuration for the detail view controller
let heroConfiguration = HeroConfig()
.size(800)
.position(.centerX)
.duration(1.0)
.springiness(1.0)
// Present the detail view controller with a shared element transition
present(UINavigationController(rootViewController: DetailViewController(imageUrl)), animated: true, completion: nil)
}
}
Detail View Controller
Next, let’s modify our detail view controller to receive the shared element and display it.
import UIKit
class DetailViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Get the image URL from the navigation controller
guard let imageUrl = navigationController?.hero?.config else { return }
// Create a hero view for the detail view controller
let heroView = HeroView(frame: CGRect(x: 0, y: 0, width: imageUrl.size.width, height: imageUrl.size.height))
.image(imageUrl)
.position(x: imageUrl.size.width / 2, y: imageUrl.size.height / 2)
// Add the hero view to the detail view controller's view
view.addSubview(heroView)
// Configure the hero view for animation
heroConfiguration = HeroConfig()
.size(800)
.duration(1.0)
.springiness(1.0)
}
var heroConfiguration: HeroConfig?
func updateHero() {
// Update the hero view's position and size
guard let configuration = heroConfiguration else { return }
heroView?.frame = CGRect(x: configuration.size.width / 2, y: configuration.position.y, width: configuration.size.width, height: configuration.size.height)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Update the hero view's position and size
updateHero()
}
}
Conclusion
In this article, we explored how to implement a shared element transition between two view controllers in an iOS app using the Hero Library. We covered the basics of shared element transitions, set up Hero Library, enabled hero animations for our UINavigationController, and implemented a shared element transition between our table view controller and detail view controller.
By following these steps, you can add animations to your app’s navigation between view controllers and create a more immersive user experience.
Additional Tips and Variations
Using Custom Transitions
One of the most powerful features of Hero Library is its ability to customize transitions. You can use different classes provided by the library to create custom transitions or even override the default transition behavior.
import UIKit
class TableViewController: UIViewController {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Get the image URL from the selected row
guard let imageUrl = images[indexPath.row] else { return }
// Create a custom hero configuration for the detail view controller
let heroConfiguration = CustomHeroConfig()
.size(800)
.duration(1.0)
.springiness(1.0)
// Present the detail view controller with a shared element transition
present(UINavigationController(rootViewController: DetailViewController(imageUrl)), animated: true, completion: nil)
}
}
Using Storyboard Segues
Another option for implementing shared element transitions is to use storyboard segues. While this approach is less flexible than using Hero Library, it can be a good choice when you need to implement complex animations or don’t want to add additional dependencies to your project.
import UIKit
class TableViewController: UIViewController {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Get the image URL from the selected row
guard let imageUrl = images[indexPath.row] else { return }
// Present the detail view controller with a storyboard segue
performSegue(withIdentifier: "detailSegue", sender: self)
}
}
import UIKit
class DetailViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Get the image URL from the navigation controller's segue data
guard let imageUrl = navigationController?.segueData()?.object as? ImageURL else { return }
// Create a hero view for the detail view controller
let heroView = HeroView(frame: CGRect(x: 0, y: 0, width: imageUrl.size.width, height: imageUrl.size.height))
.image(imageUrl)
.position(x: imageUrl.size.width / 2, y: imageUrl.size.height / 2)
// Add the hero view to the detail view controller's view
view.addSubview(heroView)
// Configure the hero view for animation
let heroConfiguration = HeroConfig()
.size(800)
.duration(1.0)
.springiness(1.0)
}
var heroConfiguration: HeroConfig?
func updateHero() {
// Update the hero view's position and size
guard let configuration = heroConfiguration else { return }
heroView?.frame = CGRect(x: configuration.size.width / 2, y: configuration.position.y, width: configuration.size.width, height: configuration.size.height)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Update the hero view's position and size
updateHero()
}
}
By following these tips and variations, you can customize your shared element transitions to fit your app’s unique needs.
Last modified on 2024-05-03