1

I'm trying to create a customized NavigationViewController where the Navigation bar is a swipeable bar at the top that controls the transitions (think UITabBarController but with swipe gestures not buttons). Here is a quick mockup. I apologize for the crudeness

I have the header bar set up as a ScrollView. I have been able to successfully detect the scroll amount using the scrollViewDidScroll method. So I have the header bar portion rigged up. I now need to implement the transition movement in the scrollViewDidScroll method.

I have looked up the Apple Documentation on how to embed view controllers inside each other but it hasn't really helped explain how to do this. The documentation mentions calling the addChildViewController: method and a bunch of other methods which are fine if I want to make the viewControllers disappear and reappear instantly, but in this scenario I'm finding hard to do it interactively.

Do I create a snapshot of the current VC and then move it? But then what exactly am I moving? In the picture for example, am I moving the entire RedVC's to the left? But then how do I get a snapshot of the BlueVC if it starts moving from outside the frame? What if I want to load in images asynchronously in the BlueVC? Will I have to use a placeholder snapshot with placeholders until the BlueVC snaps in place?

This is all becoming so convoluted... I've done stuff like this separately (snapshots, custom VC transitions, etc..) but I'm not comfortable enough in combining them all in a case like this. I'm sure I can hack up some way given enough time, but I want to learn what is the best, cleanest way.

I appreciate any help! Thanks.

Edit after accepting @MilanNosáľ's answer:

I ended up using his framework as linked in this repo. It's not interactive yet, but I can figure out the rest using what they've very graciously done for me. I wish I could post the full code here, but that's not very practical. The repo will remain up indefinitely for future SO travelers.

JoeVictor
  • 1,806
  • 1
  • 17
  • 38
  • I'm gonna shamelessly advertise my own open-source project, in which I am working with similar tasks.. so feel free to get inspiration from there, or even to contribute: https://github.com/MilanNosal/InteractiveTransitioningContainer – Milan Nosáľ Jan 18 '18 at 19:16
  • 1
    This might be what I'm looking for. It's clean, interactive and extensible. I'm gonna need a few hours to look into it deeply and customize it, but I'll edit this comment as soon as I've tried it out! – JoeVictor Jan 18 '18 at 19:27
  • 1
    It took up many hours to dig deep enough to recreate most of the functionality.. I definitely recommend reading those articles I mention there (if you haven't yet).. I'm gonna add that comment as an answer, just to get more promotion :) – Milan Nosáľ Jan 18 '18 at 19:30
  • @MilanNosáľ reading them right now! – JoeVictor Jan 18 '18 at 19:32
  • 1
    Can you share the top part? – Milan Nosáľ Jan 21 '18 at 10:49
  • @MilanNosáľ https://github.com/YoussefV/CrossNavigationController (I recommend reading the readme as the HeaderView behaves a bit differently than in the post. Transitioning logic is all limited to one function in the `HeaderViewScrollDelegate` extension, though! – JoeVictor Jan 21 '18 at 12:42
  • OK, I tried to wire it up with my container, on-interactive transitions work (I guess as you would expect).. though interactive ones will be more complex - I left you few notes there on how to start about it.. P.S.: my changes are a bit messy, you can clean the code a bit.. P.S.S.: Note that I used a different view controller than you - in my project I don't support storyboards, maybe later I will update it to support them, but now you'll have to work with code.. – Milan Nosáľ Jan 21 '18 at 17:57
  • (see pull request on github) – Milan Nosáľ Jan 21 '18 at 17:58
  • That's awesome! Pull Request Merged! I can figure out the interactivity and the rest myself. I'll push the final version when I'm done! – JoeVictor Jan 21 '18 at 19:46

3 Answers3

2

I'm gonna shamelessly advertise my own open-source project, in which I am dealing with similar tasks - InteractiveTransitioningContainer. It's goal was to prepare a framework for implementing custom containers that allow interactive transitions between its child controllers. While this may not be a direct answer to the question, I spent many hours try to provide the same environment for the child controllers as standard containers do - e.g., make sure their view(Will|Did)(A|Disa)ppear callbacks are called in right order - I had to experiment with the UINavigationController to analyze its behavior, etc.

So if nothing else, maybe you'll find some inspiration/knowledge there.

Milan Nosáľ
  • 19,169
  • 4
  • 55
  • 90
  • Hey, so I've been trying to understand your implementation for the InteractiveTransitioningContainer you linked, but unfortunately I don't quite understand how it works. What would I need to change to make it work like I mentioned above? Currently the best I can do is add it to a project's AppDelegate and have it take control of the entire screen, which is not what I want. I only want it to be under the header bar which is what controls it (like in the mockup) – JoeVictor Jan 19 '18 at 13:43
  • If you could explain the file structure and what each file does, it would help a lot. The code has almost no comments so it's very hard to follow along – JoeVictor Jan 19 '18 at 13:44
  • @QuantumHoneybees I'll hope I'll get to it during the sunday. `SwipeToSlideAutolayoutInteractiveTransitioningContainer` that's used in the example is a concrete eimplementation of a custom container - in this case something very similar to `UIPageViewController` - In your case you want to use `SwipeToSlideAutolayoutInteractiveTransitioningContainer`, or better its superclass - `SwipeToSlideInteractiveTransitioningContainer` - as an insipiration for your own container. Looking at your mockup I think we should be able to implement it. Sorry that I won't get to it till sunday. – Milan Nosáľ Jan 19 '18 at 13:51
  • So what I need is to replace everything in the SwipeToSlideImpl folder with my own implementation based on what I want? – JoeVictor Jan 19 '18 at 13:57
  • Or is it just the `SwipeToSlideInteractiveTransitioningContainer`? – JoeVictor Jan 19 '18 at 13:58
  • 1
    @QuantumHoneybees I believe that what you want is to subclass `InteractiveTransitioningContainer` (as `SwipeToSlideInteractiveTransitioningContainer` does), and implement all the other components needed for the `InteractiveTransitioningContainer` to work.. I don't feel confident to tell you the exact steps since it's been few months since I last contributed to it, but if you can wait through weekend, I believe I should be able to create a basic mockup of what you want – Milan Nosáľ Jan 19 '18 at 14:00
  • @QuantumHoneybees you can try it yourself, but thanks to my commenting style you'll have a hard time to get around - it's a pretty complex code. But I need to get into it, it's far from finished, so the sooner I'll get back to it, the better for me. This might be a good motivation, plus something like a proof-of-concept - if I cannot implement it by subclassing `InteractiveTransitioningContainer`, then it failed its purpose – Milan Nosáľ Jan 19 '18 at 14:13
0

What you really needs is creating custom segue to move from the current VC to the destination VC and override perform method like that , in this code snippet current VC moves up and destination animates from bottom to top , feel free to change any way

    override func perform() {
        // Assign the source and destination views to local variables.
        var firstVCView = self.sourceViewController.view as UIView!
        var secondVCView = self.destinationViewController.view as UIView!

        // Get the screen width and height.
        let screenWidth = UIScreen.mainScreen().bounds.size.width
        let screenHeight = UIScreen.mainScreen().bounds.size.height

        // Specify the initial position of the destination view.
        secondVCView.frame = CGRectMake(0.0, screenHeight, screenWidth, screenHeight)

        // Access the app's key window and insert the destination view above the current (source) one.
        let window = UIApplication.sharedApplication().keyWindow
        window?.insertSubview(secondVCView, aboveSubview: firstVCView)

        // Animate the transition.
        UIView.animateWithDuration(0.4, animations: { () -> Void in
            firstVCView.frame = CGRectOffset(firstVCView.frame, 0.0, -screenHeight)
            secondVCView.frame = CGRectOffset(secondVCView.frame, 0.0, -screenHeight)

            }) { (Finished) -> Void in
                self.sourceViewController.presentViewController(self.destinationViewController as UIViewController,
                    animated: false,
                    completion: nil)
        }

    }

see more info is here custom-segue-animations

Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • Thanks for the response, but how do I add interactivity to this? This seems like a set animation that is triggered when I segue between the two view controllers, which is not exactly what I am looking for in this case – JoeVictor Jan 18 '18 at 19:23
  • what do you mean by interactivity ?? – Shehata Gamal Jan 18 '18 at 19:24
  • I mean I want it rigged up so that when the user swipes the header bar to the left, the child VC is also swiped to the left, and the new VC begins to show. But if the user doesn't let go of the swipe, he can still go back to the old VC without having segued completely. – JoeVictor Jan 18 '18 at 19:26
  • you may try pageViewController – Shehata Gamal Jan 18 '18 at 19:27
0

I initially had Milan's answer selected as the final answer to the question. But, after I tried working on it for the past few weeks, with a lot of help from him, we both agreed it was too difficult to integrate his framework into a format useable for this task. I'm now working on just using a UIScrollView for the ViewControllers below, and let the HeaderView above (the thing with the labels) control the ViewControllers' scroll view below.

JoeVictor
  • 1,806
  • 1
  • 17
  • 38