Saturday, September 8, 2012

Introduction to MonoTouch Storyboard Tab Bar Controller with Navigation Controller Part 2 of 2

In Part 1 of my blog posting I explained how to get a Storyboard Tab Bar Controller app up and running in MonoDevelop.  If you haven't read Part 1 yet - I highly recommend you do so your not lost.

For those of you that like Screen Casts - I've uploaded video on how to do these steps here.

In this posting I'm going to explain how to get a Navigation Controller added to the test project along with adding three new views hooked into the Navigation Controller to go back and fourth between.  This is along posting like the prior blog post so I recommend getting some lunch and a soda prior to reading this.

In MonoDevelop I'm going to add three new ViewController classes.  I'm going name them Page1ViewController, Page2ViewController, and Page3ViewController.  I'm going to use the same method as described in the previous posting using File -> New -> File from the MonoDevelop toolbar and selecting MonoTouch and iPhoneViewController.  Next to do some spring cleaning I'm removing the extra XIB files Page1ViewController.XIB, Page2ViewController.XIB, and Page3ViewController.XIB.   Finally I'm going to modify the Constructor method signature for these three new classes to add my integer pointer to the signature.  You should have something in your project similar to what's displayed in Figure 1.

Figure 1:  Page3ViewController constructor signature modified


Make sure you modified all three's Constructor signatures before moving on.  Now that we have some View Controllers for our new views let's add them to our GUI.  To do this we need to open our StoryBoard up in XCode's Interface Builder by double clicking on the MainStoryBoard.storyboard file.

There are several ways to do the next few steps, I'm going to use the way I used to do this using Interface Builder 3.0 prior to it's marriage to Xcode.  While I'm sure someone will argue there are more efficient ways to do this in Xcode 4.0, this is the way I'm comfortable doing it.

In XCode I'm gong to drag out a new ViewController from the toolbox located in the lower right hand corner.  I should now have an empty ViewController window in my GUI designer with no lines drawn to it, etc.   In Figure 2 I highlighted the new ViewController along with where it shows up on the left hand side of the GUI Design area.

Figure 2:  New ViewController added to the GUI design area highlighted


Next I'm going to change the new ViewController's class to inherit from Page1ViewController.  This should be familiar as I went over this in the previous blog post.  With the ViewController highlighted I'm going to select the identity inspector in the upper right hand corner of XCode and under Custom Class I'm going to select Page1ViewController from the pull down list as shown in Figure 3.


Figure 3:  Setting ViewController class to Page1ViewController from the identity inspector


We now have a Page1ViewController out in our GUI area not connected to anything (no lines drawn to it).  I would like to have Page1ViewController be the first view that links to Page2ViewController and Page3ViewController.  We need a Navigation Controller to do this.  Select Page1ViewController in the GUI design area.  It's critical to make sure it's the only thing selected (it should be highlighted in blue).  Next select Editor ->  Embed In -> Navigation Controller from the Xcode Toolbar menu as shown in Figure 4.


Figure 4: Embedding Page1ViewController into a Navigation Controller


It's slick - you should see a Navigation Controller pop out with some cool Core Animation and it should now be hooked into Page1ViewController.  On top of this we now have a Navigation Bar at the top of both the Navigation Controller and Page1ViewController as shown in Figure 5.


Figure 5:  new Navigation Controller hooked to Page1ViewController


Now it would be nice if our Tab Bar would show up on our Navigation Controller and Page1ViewController views.  To do this we need to configure them to include the Tab Bar in there view.  This will reserve the area on the View so we don't drag any controls into the View in that area by accident.  Select Page1ViewController and select the Attribute inspector from the upper right hand part of Xcode.   From the list of Attributes change the Bottom Bar to Tab Bar from the pull down list.  It will change the bottom of the view to a black Tab Bar strip.  Repeat this step for the Navigation Controller so it also has it's Bottom Bar attribute set to Tab Bar.



Figure 6:  switching the Bottom Bar attribute to Tab Bar on Page1ViewController


Currently our Navigation Controller is NOT connect to our Tab Bar Controller.  Because of this, if we were to Save and try to build this application we can't access the Navigation Controller or Page1ViewController.  To fix this we need to connect our Navigation Controller to the Tab Bar Controller.  Select the Tab Bar Controller in the GUI Designer area  (make sure it's hight lighted blue) and control drag from the Tab Bar Controller to the Navigation Controller.  Select View Controller under Relationship Segue from the pop-up window as shown in Figure 7.

Figure 7:  connecting the Tab Bar Controller to the Navigation Controller


As you probably figured out we now have a line drawn between the Tab Bar Controller and the Navigation Controller.  Xcode was nice enough to add a Tab Bar Item to our Tab Bar on our Navigation Controller called Item.  Let's change the name of it to "Foo" for our testing purposes.  To do this click on the Tool Bar item in the Navigation Controller.  From the Attributes inspector change the Title to Foo as shown in Figure 8.

Figure 8:  Changing Tool Bar Item title to Foo


I like to test my changes from time to time to make sure I didn't screw up anything in my application.  This is a great time to test all these changes before moving forward.  In Xcode use File -> Save and then XCode -> Quit Xcode to go back to MonoDevelop.  From MonoDevelop Star Debugging the project.  You should now have 4 Tool Bar items in the simulator including our new item named Foo.  When selecting our Foo item you will notice our new Page1ViewController pop's up and you can see a blank View with the Navigation Bar on it as shown in Figure 9.   This has all been done without writing any code so far to push or pop views from our View Controllers.  VERY COOL!!


Figure 9:  iPhone Simulator with new Page1ViewController's view selected


Now we are sure we are on the right track let's head back to Xcode and add in some more views to connect our Page2ViewController and Page3ViewController classes to.  Close the iPhone Simulator and double click on your MainStoryboard.board file to open it up in XCode's Interface Builder.

To keep track of which ViewController is which I recommend adding a title to the Navigation Bar on Page1ViewController.  To do this double click on the Navigation Bar and give it a title of Page 1.

Next let's drag two more ViewController objects onto the GUI Designer.  Now that we have two new ViewController objects we need to change there classes to be Page2ViewController and Page3ViewController so we can access any objects in there view's via code.  To do this select the first new ViewController and click the identity inspector and change the Custom Class drop down list and select Page2ViewController.  Rinse and repeat this step for the other one but this time select Page3ViewController. These are the same steps we did in Figure 3 of this posting.

Let's also add the Tab Bar  to Page2ViewController and Page3ViewController.  Again select each one and from the Attributes inspector change the Bottom Bar to Tab Bar.  This is the same steps we did in Figure 6 of this posting.

From here on is the meat of this posting - i.e. setting up the various views to "push" and "pop" between each other with NO CODE.

Let's add a button so we can forward between Page1ViewController and Page2ViewController.  From the Toolbox drag a Bar Button Item to the right hand corner of the Navigation Bar on Page1ViewController.  You should now have a button named Item in the Navigation Bar.  I recommend renaming that button to Page 2 as when we click on the button we want Page2ViewController's view to be displayed.  You can do this by double clicking on the Bar Button and renaming it Page 2.  At this point in time your Page1ViewController would look similar to Figure 10.


Figure 10:  Added new Bar Button to the Navigation Bar of Page1ViewController



This is the trickest part of the entire process.  We need to tell Page1ViewController when the Bar Button labeled Next is clicked we want to push Page2ViewController into View.  To do this, we need to make sure we have Bar Button labeled Next selected in the GUI Designer.  You should notice it is high lighted while the rest of the View Controller is dimmed.  Control drag from the Bar Button Next to Page2ViewController and let go of your mouse.  Select Push from the Manual Segue.  Page2ViewController is now connected to Page1ViewController.  You should also notice that Page2ViewController now has a Navigation Bar just like Page1ViewController (well minus the Bar Button).  Again all this without any code so far!

Let's change the Title of Page2ViewController to read "Page 2".  To do this double click on the Navigation Bar and add the text Page 2.  At this point in time my Xcode looks like Figure 11.



Figure 11:  Page2ViewController connected to Page1ViewController in Xcode


We are almost done.  Let's drag another Bar Button Item onto Page2ViewController in the upper right corner of the Navigation Bar.  Rename the button to Page 3.  Now as we did above let's Control drag from the new Bar Button labeled Page 3 to Page3ViewController and select Push from the Manual Segue.  We should now have a Navigation Bar on Page3ViewController.  Double click in the Navigation Bar of Page3ViewController and give it a label of Page 3 as shown in Figure 12.


Figure 12:  Page 3 Navigation Bar with all view connected



At this point in time we now have Page1ViewController connected to Page2ViewController and Page2ViewController connected to Page3ViewController.  To test select File -> Save in Xcode and then Xcode -> Quit Xcode from the Xcode Toolbar.  In MonoDevelop click Star without Debugging button on the toolbar.  The iPhone Emulator should appear.  Clicking on the 4th tab bar item labeled Foo will bring up our Page1ViewController.  By clicking on the Page 2 button we will switch to Page2ViewController.  By clicking the Page 3 button we will switch to Page3ViewController.

You can click back and forth and go between all the view's without having to have written a drop of code to Push and Pop from a Navigation Controller.  I hope you can see the advantages of Storyboard's and how they can save you in writing code which ultimately will make you more efficient 

-Costoda




Introduction to MonoTouch Storyboard Tab Bar Controller with Navigation Controller Part 1 of 2

Today I wanted to explain how I setup a Storyboad app up and running with MonoTouch.  These directions are long, so grab a soda and lunch first before you dive into reading these.  I assume you have a clue on how to use MonoDevelop and XCode's Interface Builder.

For those that link to watch Screen Casts - I've uploaded a view that explains this blog posting here.

If you don't know anything about Storyboards go read this blog - while all the code examples are in Object-C it does an excellent job to explain Storyboard's and the advantages of them:

http://www.raywenderlich.com/5138/beginning-storyboards-in-ios-5-part-1

My goal was to have an App that had both Tab Controls on the bottom AND Navigation bar at the top.  Prior to Storyboards it took some code to push and pop views from your Navigation Controller.  On top of this you would have a project full of XIB files.  With Story Boards, all that code is gone along with the XIB files.  Pretty much all your GUI stuff lives in the Storyboard file.  I HIGHLY recommend looking into Storyboard - it has the ability to save you A LOT of time.  Here is my sudo explanation of what I did:

Started a new MonoTouch Solution.  From there I selected C# -> MonoTouch -> iPhone Storyboard -> Tabbed Application.  Gave it some kind of test name.


Figure 1:  Start a new Storyboard project

What you just bought was a new fancy project with two View Controllers (FirstViewController and SecondViewController).  Along with this you get a MainStoryboard.storyboard file.  This is a replacement for all your XIB files.  If you compile and run you have a new fancy app with two tab options at the bottom that are hooked to your two View Controllers (FirstViewController and SecondViewController).  Slick - no code so far...  

If you double click the MainStoryboard file you will launch XCode and your new Storyboard will display your current two views hooked into a Tab View Controller.


Figure 2:   Tab Bar Controller with two View Controllers

Note at the bottom left hand corner if your "UI" controls grid to the right if the object selector is three buttons used to Zoom in and Out. If you have a smaller screen, these buttons are going to be critical to zoom in and out to find the various views you have in your Storyboard.   In another application I'm working on I have 10 views and with a 27" Thunderbolt display I still find myself zooming in and out a lot.  

So to start out I would like to add another View to my tab view.  Several ways to accomplish this.  You can drag a View Controller from the object selector toolbox - that's the way I like to do it.  Another way is to copy one of the existing views and paste it in.  I'm going to drag a new View Controller out from the toolbox.  You should have something similar to what shown in Figure 3.
Figure 3:  New View Controller added to Storyboard


To connect thew new view to your existing Tab Bar Controller select the Tab Bar Controller and Control-Drag over to the new View Controller.  Let go of the mouse and select view controllers under Relationship Seque.  

Figure 4:  Connecting new view to Tab Bar Controller


Let's save this and go back to MonoDevleop as we need add a new ViewController .cs file we can link to our new View Controller.   I'm sure there is an easier way to do this, but I don't know of one yet - so in my example I'm going to handle it the only way I know how.   In MonoDevelop we need to add a new ViewController so select File -> New -> File from the toolbar.  From the New File window select MonoTouch and iPhone View Controller from the options listed.  I'm going to name my ThirdViewController to keep up with the theme in my current project.


Figure 5:  Adding a new iPhone View Controller to the project

You will end up with a new ThirdViewController.cs and ThirdViewController.xib file.  Wait - I said you didn't need those anymore.  Yep, that's true so we are going to delete that XIB file.  You can right click on the XIB file and select Remove.  It will ask if you want to delete it, select Delete button.  Right now our new ThirdViewController.cs file is linked to the XIB file we just deleted.  We need to fix that. Open the ThirdViewController.cs file and locate the method signature for the Constructor method.  This is the Method name that is the same as the Class name.  You will notice that currently it calls it's base class passing in the signature line a string class name and null.  Storyboard doesn't use strings to find the view - it uses a integer pointer to find the view in the Storyboard file.  So to fix this we are going to change the signature of the base call to:

public ThirdViewController (IntPtr handle) : base (handle)

If you are confused look at the way the FirstController.cs and SecondController.cs classes constructor signatures look.  You need to match that.

Figure 6:  Changing the method signature in the new ThirdViewController class



Save your code changes and double click on the Storyboard file to call it up in Xcode's Interface Builder.  Select your new View Controller that you dragged out a few steps ago.   You will know when you have it selected as the entire view will have blue line around it.  Use the Inspector area to the top right of the designer view and select the third little icon call the identity inspector.  You will see there is a listing of the class and it's currently set to UIViewController in grey text.  We are going to select the pull down list and select our new ThirdViewController from the list.  See Figure 7 if you are lost.

Figure 7:  Changing the class that the selected View Controller inherits from

That's it, the selected ViewController will now use the ThirdViewController class code file.  You can test this by dragging a Label onto the View.  Now switch to the assistant editor view using the little tuxedo icon under the editor heading on the Toolbar.  This opens your code file and the Interface Builder next to each other.  Control drag over from your label to your code file before the @end and let go to create a new Outlet.  A window will pop up asking you to name your Outlet.  I'm going to name mine labelTest. Yep I know lack of originality.  Save all this and go back to MonoDevelop.  In your ThirdViewController.cs file locate the ViewDidLoad() method.  After the base.ViewDidLoad(); call add some code to change the text of your label you just added.  I'm going to just change mine to be "Hello World".

Figure 8:  Changing the label text to "Hello World"
 


Test all your changes by start debugging.  The iPhone Emulator should come up.  You should have three tabs you can select between.  When clicking on your new third one labeled Item with no icon you should have your label set to Hello World.


Figure 9:  iPhone Emulator with new View


Click here for Part 2 that explains how to add a Navigation Controller to this project.