Hero: ViewController Containment support

Created on 29 Jan 2018  路  8Comments  路  Source: HeroTransitions/Hero

Hi @lkzhao,
thanks for great library.

Currently I'm prototyping an app in Storyboard and would like to use Hero for some transitions.

Is it possible to use Hero with _ContainerView_ and _Embed_ segue?
I saw a similar issue has been raised (#153), but has this functionality been implemented?

Most helpful comment

OK, I've looked into this a bit more and here's what I've found.

Multiply-nested view controllers aren't an issue at all since Hero looks primarily at the view hierarchy. It doesn't really care that much about view controllers; all the view controller stuff in the API is just there to impedance-match with Apple's underlying transition API. As long as you get the "before" and "after" states set up fully before transitions, it just works.

The real b锚te noir in my setup turns out to be UISearchController. The way it's implemented is kind of wacky - look at the view debugger in Xcode when you're browsing search results and you'll see that you're off in some modal presentation that has nothing to do with the navigation controller hierarchy perceived by the user. When you transition to a detail view, there's no obvious way for Hero to get its hands on the right pair of root views.

I actually tried implementing a little hack that would let view controllers say "this is my real view" to Hero, but it caused crashes, so it didn't seem like a promising avenue. I ended up essentially reimplementing my own version of UISearchController that uses a saner containment hierarchy, and that seems to be working fine.

Hero transition animations for container views also work fine, with some additional glue added. The issue is that you have to continue to do the manual view-controller-hierarchy management while also calling Hero.shared.transition, and it's not entirely clear at exactly what point that call should go. This is what I've been using; seems to work so far, but I'm not 100% sure there isn't a latent problem here:

func transitionTo(_ controller: UIViewController, animated: Bool = true) {
    let outgoingController = childViewControllers.last
    if animated && Hero.shared.isTransitioning && outgoingController != nil {
        // print("Transitioning!")
        Hero.shared.complete(finished: true)
    }
    outgoingController?.willMove(toParentViewController: nil)
    outgoingController?.removeFromParentViewController()
    addChildViewController(controller)
    if animated, let outgoing = outgoingController {
        Hero.shared.transition(from: outgoing, to: controller, in: containerView) { finished in
            controller.didMove(toParentViewController: self)
        }
    } else {
        containerView.addSubview(controller.view)
        controller.view.frame = containerView.bounds
        controller.didMove(toParentViewController: self)
    }
}

I'm not sure that the handling of the cases where Hero already isTransitioning are handled correctly, either. (In my application, there can be a very quick transition from a "loading" view controller to a standard detail view, faster than the animation time.)

Bottom line for me: I think all the pieces are already in Hero. It might be helpful to include something like the transitionTo method above that includes view controller changes, just because it's not self-evident how to write this without some experimentation. Either that, or provide some kind of stepwise API that does not manage the subview change (e.g., recordInitialView() followed by recordTargetView() and animate()).

All 8 comments

ContainerView is not supported at the moment. But there is an API available called

  Hero.shared.transition(from: UIViewController, to: UIViewController, in view: UIView, completion: ((Bool) -> Void)? = nil)

It basically allows you to provide two VC and a containerView and apply transition animation between the first view controller to the second one. try that out and see if it works for you.

That might work for my case, I need to try.

This could be a "nice to have" feature, as it allows using Hero as a prototyping framework.

Storyboards have a drawback with reusability. It can be solved easily by using References and VC Containment where ContainerView points to a Storyboard reference.

Incorporating Hero with its default transitions will make these prototypes look extremely realistic, and they can be done as quickly, as prototypes done in specialized software (e.g. Origami / Pixate etc).

@richardtop Did this solve it for you? I'm also after container support.

@J7mbo I finished the prototype faster than I was able to try this feature.

Hi,

First of all thanks for such useful library 馃憤

I am using multiple ContainerViews in my "TargetVC" connected to tabs (to be able to switch in between). These ContainerViews embed UITableViewControllers. Data is loaded from network. Network data is small and total time to get data is around 50ms.

As you mentioned above i tried to use "Hero.shared.transition" but i guess i could not apply correctly :(
Lets say there are :

  • HomeVC
  • TargetVC
    . containerView
    . - TargetVC_ChildTableVC

To be able to have a smooth cascade animation (as in Documentation) where shall i implement "Hero.shared.transition"

Another question; if i want to display "TargetVC_ChildTableVC" to come from bottom of the screen (at the same time with other animations) after table view contents loaded/rendered . What shall i need to do?

Best

If i can manage to do :

I want to display "TargetVC_ChildTableVC" to come from bottom of the screen after table view contents loaded/rendered. Currently Hero animates the ContainerView first and then load the table data of embedded TableViewController.

will be more than enough for me.

I'm just evaluating Hero at this point and haven't written any Hero code. It looks really nice - exactly the kind of morphing I was looking for. However, this "indirect view controller transition" issue is a potential sticking point for my use case as well.

I'll outline my specific VC structure and use case below just for reference, but I don't want to bury the lede. The main reason I'm posting here is to ask what the current status on this is and to ask if you'd be open to a PR in this area if I were to implement it. If so, do you have any specific thoughts or plans regarding the API for it?

In my app, every state for an area is a separate view controller. So, for example, in the Search function, there's one VC that owns the overall search function. I'm using a UISearchController, which by design segregates the presentation of search results into a separate view controller. That view controller in turn is just a big container view that swaps in sub-controllers for states such as "searching spinner animation", "there was a network error", or the presentation of actual search results in a table view.

I outline this in terms of Search, but it's really a more general pattern. For example, one transition I would like to animate is from a tap on a search result to a detail presentation:

herotransition

I just want to do the obvious transition animation anchored to the image. But the destination is actually a PodcastViewController that manages a separate container view, into which (in the typical case) it installs a PodcastStandardStateViewController.

It's possible that the existing API might handle this just fine. I'm just a bit unsure about the common container view. There's really nothing in common between the two view hierarchies until you get back into the navigation controller.

OK, I've looked into this a bit more and here's what I've found.

Multiply-nested view controllers aren't an issue at all since Hero looks primarily at the view hierarchy. It doesn't really care that much about view controllers; all the view controller stuff in the API is just there to impedance-match with Apple's underlying transition API. As long as you get the "before" and "after" states set up fully before transitions, it just works.

The real b锚te noir in my setup turns out to be UISearchController. The way it's implemented is kind of wacky - look at the view debugger in Xcode when you're browsing search results and you'll see that you're off in some modal presentation that has nothing to do with the navigation controller hierarchy perceived by the user. When you transition to a detail view, there's no obvious way for Hero to get its hands on the right pair of root views.

I actually tried implementing a little hack that would let view controllers say "this is my real view" to Hero, but it caused crashes, so it didn't seem like a promising avenue. I ended up essentially reimplementing my own version of UISearchController that uses a saner containment hierarchy, and that seems to be working fine.

Hero transition animations for container views also work fine, with some additional glue added. The issue is that you have to continue to do the manual view-controller-hierarchy management while also calling Hero.shared.transition, and it's not entirely clear at exactly what point that call should go. This is what I've been using; seems to work so far, but I'm not 100% sure there isn't a latent problem here:

func transitionTo(_ controller: UIViewController, animated: Bool = true) {
    let outgoingController = childViewControllers.last
    if animated && Hero.shared.isTransitioning && outgoingController != nil {
        // print("Transitioning!")
        Hero.shared.complete(finished: true)
    }
    outgoingController?.willMove(toParentViewController: nil)
    outgoingController?.removeFromParentViewController()
    addChildViewController(controller)
    if animated, let outgoing = outgoingController {
        Hero.shared.transition(from: outgoing, to: controller, in: containerView) { finished in
            controller.didMove(toParentViewController: self)
        }
    } else {
        containerView.addSubview(controller.view)
        controller.view.frame = containerView.bounds
        controller.didMove(toParentViewController: self)
    }
}

I'm not sure that the handling of the cases where Hero already isTransitioning are handled correctly, either. (In my application, there can be a very quick transition from a "loading" view controller to a standard detail view, faster than the animation time.)

Bottom line for me: I think all the pieces are already in Hero. It might be helpful to include something like the transitionTo method above that includes view controller changes, just because it's not self-evident how to write this without some experimentation. Either that, or provide some kind of stepwise API that does not manage the subview change (e.g., recordInitialView() followed by recordTargetView() and animate()).

Was this page helpful?
0 / 5 - 0 ratings