Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API for manually specifying views to animate #74

Closed
jlongster opened this issue Feb 8, 2017 · 8 comments
Closed

API for manually specifying views to animate #74

jlongster opened this issue Feb 8, 2017 · 8 comments

Comments

@jlongster
Copy link
Contributor

I'm working on an integration with React Native, and I'm at the point where I think I can get this working if I have one thing: a function that will start an animation given an array of from views an and array of to views. If you look at Hero.start, most of the code only deals these lists of views from HeroContext.

Am I wrong in thinking that if on the React Native side I do all the work to figure out the from/to views, that I could get integration with Hero working if we provide that API? It would bypass parts of Hero that do the storyboard integration and automatically hooking up views, and only do the animations.

@lkzhao
Copy link
Collaborator

lkzhao commented Feb 8, 2017

Currently, Hero requires a source root view, a destination root view, and a container view to animate these.

Such API with lists of from/to views within one VC can be built though. There are some problem with handling view hierarchy, but should be possible.

Glad to hear that someone is working with React Native. If you would like to continue working on it, I can provide this API in a few days. One thing to consider on your side, when animating in react, heroID shouldn't be used much. For existing views, you should know the destination state from react native and assign these as heroModifiers. These should be the fromViews. The toView list should be only the added views. The 'useNoSnapshot' modifier might also be useful.

We can talk about this in detail if you wish to continue. Let me know. I am super excited about this!

@jlongster
Copy link
Contributor Author

Don't worry about this too much for now! I am experimenting myself with a few things first and I'll let you know what I learn. I have something basically working but I'm still playing with how it should all work.

when animating in react, heroID shouldn't be used much

Yep, although I ran into one issue: MatchPreprocesser().process forces the view to have a heroID. I think if it didn't force it there, I wouldn't need heroID at all; unfortunately right now I need to patch it on dynamically.

you should know the destination state from react native and assign these as heroModifiers

That's interesting. What I'm trying right now it to just give Hero the two native views that are controlled by react native, and let it take snapshots and simply animate the snapshots. Because the dest state has been applied to the real view, Hero can get it from there. I have a prototype working right now but I'll get back to you if this actually works.

I will follow up with this later. This is for a client and the app isn't open-source, but I can extract what I figure out soon and talk about it with you.

@lkzhao
Copy link
Collaborator

lkzhao commented Feb 12, 2017

Checkout HeroIndependentController class in the latest version.
That might be what you need. Haven't tested it at all though.

@jlongster
Copy link
Contributor Author

jlongster commented Feb 14, 2017

This is awesome! It's much closer to what we need. However, there seems to be a few tweaks needed.

It looks like I need to clean up after the animations and call this code:

    self.hero.context.unhideAll()
    self.hero.context.removeAllSnapshots();

I tried to do that in the completion callback but the hero context was already destroyed. So I had to tweak it to call the completion callback before destroying the context.

Another thing is we lose out on the functionality of snapshotting the fullscreen and displaying a snapshot while beginning the animation. At least on the simulator, I could see the flickering, so I implemented the same code myself. This stuff:

      self.fullScreenSnapshot = containerView.window?.snapshotView(afterScreenUpdates: true) ??
        fromRootView.snapshotView(afterScreenUpdates: true)
      (containerView.window ?? containerView)?.addSubview(self.fullScreenSnapshot)

However, I need to remove the snapshot before animating but there was no callback for that. So I also added an animation callback. The full changes are below:

diff --git a/Sources/HeroBaseController.swift b/Sources/HeroBaseController.swift
index 91016fb..2de293c 100644
--- a/Sources/HeroBaseController.swift
+++ b/Sources/HeroBaseController.swift
@@ -345,22 +345,22 @@ internal extension HeroBaseController {
     defaultAnimator = nil
     progressUpdateObservers = nil
     transitionContainer = nil
     completionCallback = nil
     container = nil
     processors = nil
     animators = nil
     plugins = nil
-    context = nil
     beginTime = nil
     progress = 0
     totalDuration = 0
 
     completion?(finished)
+    context = nil
   }
 }
 
 // MARK: Plugin Support
 internal extension HeroBaseController {
   static func isEnabled(plugin: HeroPlugin.Type) -> Bool {
     return enabledPlugins.index(where: { return $0 == plugin}) != nil
   }
diff --git a/Sources/HeroIndependentController.swift b/Sources/HeroIndependentController.swift
index 0d94d1a..92057e5 100644
--- a/Sources/HeroIndependentController.swift
+++ b/Sources/HeroIndependentController.swift
@@ -18,24 +18,32 @@
 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
 import UIKit
 
 public class HeroIndependentController: HeroBaseController {
+  internal var animationCallback: (() -> Void)?
+
   public override init() {
     super.init()
   }
 
-  public func transition(rootView: UIView, fromViews: [UIView], toViews: [UIView], completion: ((Bool) -> Void)? = nil) {
+  public func transition(rootView: UIView, fromViews: [UIView], toViews: [UIView],
+                         animation: (() -> Void)? = nil,
+                         completion: ((Bool) -> Void)? = nil
+  ) {
     transitionContainer = rootView
     completionCallback = completion
+    animationCallback = animation
 
     prepareForTransition()
     context.defaultCoordinateSpace = .sameParent
     context.set(fromViews: fromViews, toViews: toViews)
     processContext()
     prepareForAnimation()
+
+    animationCallback?()
     animate()
   }
 }

I'd open to other ways to solving this though. What do you think? It's so close!

@lkzhao
Copy link
Collaborator

lkzhao commented Feb 15, 2017

context should be kept nil before calling the completionCallback. This is so that the user can start another transition inside the completion.

You can override inside the HeroIndependentController

  override func complete(finished: Bool){
    context.unhideAll()
    context.removeAllSnapshots();
    super.complete(finished:finished)
  }

For the fullscreenSnapshot, not sure whats the best way. Maybe we can bake this logic inside HeroBaseController

@jlongster
Copy link
Contributor Author

I now agree that it's up to the user to implement the fullscreen snapshot. It may be nice to include that functionality in here but force the user to add/remove it, but I want to add it at a specific time (before invoking Hero) so it's nice that I control it. The only thing is that I need the animation callback to remove it.

Thanks for the tip, I will try overriding complete.

@zk
Copy link

zk commented Feb 26, 2017

@jlongster @lkzhao super exciting that you're working on this, is the WIP code up anywhere? Took a look at your fork (https://github.com/jlongster/Hero) but couldn't find the changes you were talking about above.

@senthilsivanath
Copy link

senthilsivanath commented Dec 22, 2018

@lkzhao @jlongster , any progress on this? Need this in RN.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants