Share view between controllers

MarkMadlangbayanMarkMadlangbayan USUniversity ✭✭

If I want to share a custom view amongst several view controllers. What's the best way of doing this? I'd still want to use storyboard designer or xib designer for the laying out instead of coding the ui elements.

Posts

  • adamkempadamkemp USInsider, Developer Group Leader mod

    This is one of the reasons I dislike storyboards. You can't do this with a storyboard. Every UI object in a storyboard is a unique object. You can't have two view controllers that share a UI or a piece of a UI, which is a common thing to want to do.

    What you can do is create a custom view and use a .xib for the custom view, and then you can drop instances of that custom view in different view controllers on a storyboard. I don't know if the Xamarin designer will render that or not. In Xcode at least you would just get a big blank custom view object, which isn't very helpful.

  • MarkMadlangbayanMarkMadlangbayan USUniversity ✭✭

    Is it possible to create a xib file, and somehow load that to the ViewController?

  • adamkempadamkemp USInsider, Developer Group Leader mod

    Using a .xib for a view controller is easy. The default behavior for a view controller is to look for a .xib with the same name as the class and load it automatically in LoadView. Using one for a view requires calling NSBundle.CurrentBundle. LoadNib.

  • Tom-PrattTom-Pratt GBMember ✭✭

    You can use a Container View to hold a child view controller. So you could make a view controller for your reusable UI component instead of a custom view. Then it can be embedded in any number of parent view controllers using container views.

    Fortunately in Xcode7/iOS 9, Apple introduced Storyboard References, so your reusable view controller can easily live in a separate storyboard file to the view controllers that want to contain it (just make sure it is set to be the initial view controller for its storyboard, then embed a reference to that storyboard in a container view). For me, the Storyboard Reference feature has finally made storyboards live up to expectation, because you can break them up into multiple storyboard files without needing to stitch them together programmatically.

    Seems like overkill sometimes since making custom views is so natural in Android, this is more like making a fragment. But considering the terrible way xcode renders custom views I think this must be how Apple are encouraging us to make reusable ui components.

  • MarkMadlangbayanMarkMadlangbayan USUniversity ✭✭

    Thanks @adamkemp!

    @Sylapse, interesting. Do you have a site that you can point me for more information about Container View (Xamarin)? Interesting approach.

    -Mark

  • Tom-PrattTom-Pratt GBMember ✭✭

    Don't know of any particular resources as I just played around with it originally and it's fairly intuitive once you get going, here's a super simple example I made in a couple of minutes https://github.com/Sylapse/ChildViewController.git

    It just has two storyboard files, one containing the child view controller and another with two parent view controllers that contain the child.

    The only bit of code is in ViewController.cs where we get a reference to the child view controller. Oddly it's done in PrepareForSegue, because the child view controllers are added with an embed segue.

    Hope that helps :)

  • MarkMadlangbayanMarkMadlangbayan USUniversity ✭✭

    Thank you! I noticed that I can't open the Main.storyboard from Xamarin Studio. I have to open it from XCode. Is this normal behavior?

  • Tom-PrattTom-Pratt GBMember ✭✭

    Not sure sorry. I only ever use xcode. Maybe the Xamarin designer can't yet deal with Storyboard References or something.

    Let me know how you get on if you decide to use this method. I haven't used it much and am interested to know what the capabilities and limitations are!

  • adamkempadamkemp USInsider, Developer Group Leader mod

    Container view controllers are harder to do correctly than most people think, and as a result most implementations I see are wrong. I don't encourage you to do that. The only reason to make a container view controller is if you want to reuse that view controller for multiple other child view controllers as a reusable component, like UINavigationController or UISplitViewController. If you just want some reusable views then it's easier to just make a base class view controller that has those views or make a reusable view and insert that into each view controller that needs it. You're less likely to do that wrong.

  • Tom-PrattTom-Pratt GBMember ✭✭

    Isn't creating a custom container view controller quite different to just using the container view available to storyboards?

    I agree that creating container view controllers is very fiddly when it comes to managing the lifecycles of the child view controllers and animations have to be taken into account and all that. But using a container view appears to take care of everything for you.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    I'm just saying it's done way more often than needed and usually incorrectly, and I'm not sure whether it's warranted here. Proceed with caution.

  • Tom-PrattTom-Pratt GBMember ✭✭

    Are we definitely referring to the same thing? I'm suggesting dragging a container view onto his view controllers on the storyboard and connecting them to the reusable child with an embed segue. It doesn't require you to write any code and I'm not sure how you could misuse it. Is this what you're warning against? I'm keen to know what the pitfalls of this method are if so because I have been using it and trusting it to work.

    I'm not suggesting implementing view controller containment requiring BeginAppearanceTransition, WillMoveToParentViewController, DidMoveToParentViewController or any of that more complex stuff.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    Well, that is the same thing, but it looks like the UIContainerView (seemingly only usable through a storyboard?) does some of the work for you and therefore makes it less error prone. I've never seen that. This looks like it might be a sane way to do it in a storyboard. Interesting.

  • Tom-PrattTom-Pratt GBMember ✭✭

    Yes the container view seems to handle everything for you. It works well when combined with a Storyboard Reference (also only available when editing a storyboard). It lets you place your reusable child view controller in its own file and reference it from any view controller on any storyboard in your project. The example in the repository I posted shows it https://github.com/Sylapse/ChildViewController.git

    I was never a fan of storyboards without these features, but it's probably my preferred method now that they've been added. Still waiting for some sort of colour constants though!

  • adamkempadamkemp USInsider, Developer Group Leader mod

    Well you taught me something new. Kudos!

  • AlexCorradoAlexCorrado USXamarin Team Xamurai

    @MarkMadlangbayan When you say that Main.storyboard won't open from Xamarin Studio, are you using Xamarin Studio 5.10 (available in the Beta channel)? That one works for me. If it doesn't work for you with that version, would you mind sharing the logs? Thanks!

  • Tom-PrattTom-Pratt GBMember ✭✭

    @adamkemp said:
    Well you taught me something new. Kudos!

    :smiley: But does it change your opinion of storyboards?

  • adamkempadamkemp USInsider, Developer Group Leader mod

    No, there are still too many other issues with storyboards for me to endorse them. It makes one aspect of storyboards a little better, though.

  • MarkMadlangbayanMarkMadlangbayan USUniversity ✭✭

    @Sylapse - I had to try it out before replying. I was able to share a UITableViewController between two UIViewControllers using your sample. It works, and so far it's working great.

    BTW, how do you reference a ViewController from a different Storyboard (StoryBoard Reference).

  • Tom-PrattTom-Pratt GBMember ✭✭

    Glad that seems to be doing the trick

    As far I can tell, you can only give a Storyboard Reference a particular storyboard ID. What it is actually referencing seems to be the initial view controller for that storyboard (the one with the arrow indicating that it is the entry point). So you can't reference an arbitrary view controller using a Storyboard Reference.

  • SteveShaw.5557SteveShaw.5557 USMember ✭✭✭
    edited March 2017

    You can set up custom segues to any view controller in another storyboard. I don't recall the details of doing so visually in Xamarin storyboard - we found it less confusing to maintain if we did it in code. This approach does not require segues to be defined. All it needs is a "StoryboardID" on each target ViewController. I defined these two methods:

    namespace MyApp.UI {
    
    // NOTE: "viewControllerStoryboardID" is the "StoryboardID", set on that VC in its storyboard.
    public static void GoToVC( UINavigationController nav, string viewControllerStoryboardID, string storyboardName, bool animated = true )
    {
        nav.PushViewController( GetVC( viewControllerStoryboardID, storyboardName ), animated );
    }
    
    public static UIViewController GetVC( string viewControllerStoryboardID, string storyboardName )
    {
        UIStoryboard storyboard = UIStoryboard.FromName( storyboardName, null );
        return storyboard.InstantiateViewController( viewControllerStoryboardID );
    }
    
    }
    

    The second method is useful if you want to set fields on the target controller. (If you were using storyboard segues, this would be logic you put in PrepareForSegue. We needed a similar solution for these instantiated links.) Example code in your custom view controller, to "segue" (its not technically a segue, but behaves like one) to a different view controller:

    using MyApp.UI;
    
    public void GoToThatPlace()
    {
        // NOTE: ThatPlaceViewController has a StoryboardID that is also "ThatPlaceViewController".
        var thatVC = (ThatPlaceViewController)UI.GetVC( "ThatPlaceViewController", "MyStoryboardName" );
        thatVC.MyField1 = ...;
    
        this.NavigationController.PushViewController( thatVC, true );
    }
    

    Ahhh - now our code structure is similar between iOS and Android. :smile:

Sign In or Register to comment.