Time to Code
Open MainNavigationView.xib.cs in MonoDevelop. We're going to make a few small changes, first of all, take a look at the third constructor:
public MainNavigationView () : base("MainNavigationView", null)
{
Initialize ();
}
Let's change that to this:
public MainNavigationView ()
{
NSBundle.MainBundle.LoadNib ("MainNavigationView", this, null);
Initialize ();
}
These two calls look very similar, because they are. The base class constructor loads the xib file, but does it asynchronously, which would cause our application to error (we're going to access an item in the xib file right after our constructor, in just a bit). The second implementation forces the xib file to load synchronously, so we can access its members right away.
The next thing we want to do is add the following property:
public UINavigationController NavController
{
get { return this.navMain; }
}
We're simply exposing the view's Navigation Controller. We'll see why we do this in just a bit, but basically, we'll need to get access to it so we can add it to our main window.
Next, in the Initialize method, let's add the following code:
this.btnWebBrowser.TouchDown += delegate {
this.navMain.PushViewController (new WebBrowserView (), true);
};
This wires up the TouchDown (think "Click" in the Microsoft Windows world) to load a new view controller onto the window. In this case, when someone clicks on our Web Browser button, we're going to instantiate a new WebBrowserView object and push it onto our Navigation Controller. Your MainNavigationView.xib.cs class should now look like this:
using System;
using System.Collections.Generic;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace Example_UIWebView
{
public partial class MainNavigationView : UIViewController
{
#region Constructors
// The IntPtr and initWithCoder constructors are required for controllers that need
// to be able to be created from a xib rather than from managed code
public MainNavigationView (IntPtr handle) : base(handle)
{
Initialize ();
}
[Export("initWithCoder:")]
public MainNavigationView (NSCoder coder) : base(coder)
{
Initialize ();
}
public MainNavigationView ()
{
NSBundle.MainBundle.LoadNib ("MainNavigationView", this, null);
Initialize ();
}
void Initialize ()
{
this.btnWebBrowser.TouchDown += delegate {
this.navMain.PushViewController (new WebBrowserView (), true);
};
}
#endregion
public UINavigationController NavController
{
get { return this.navMain; }
}
}
}
Now that we've made those changes made to our navigation controller screen, open up the Main.cs file. Add the following declaration to your AppDelegate class:
MainNavigationView _mainNavView;
Then, as the first calls in the FinishedLaunching method, add the following code:
this._mainNavView = new MainNavigationView (); window.AddSubview (this._mainNavView.NavController.View);
This code instantiates a new MainNavigationView screen, and then adds the view that the Navigation Controller has to the window. The main.cs file should now look like this:
using System;
using System.Collections.Generic;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace Example_UIWebView
{
public class Application
{
static void Main (string[] args)
{
UIApplication.Main (args);
}
}
// The name AppDelegate is referenced in the MainWindow.xib file.
public partial class AppDelegate : UIApplicationDelegate
{
MainNavigationView _mainNavView;
// This method is invoked when the application has loaded its UI and its ready to run
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
// If you have defined a view, add it here:
// window.AddSubview (navigationController.View);
this._mainNavView = new MainNavigationView ();
window.AddSubview (this._mainNavView.NavController.View);
window.MakeKeyAndVisible ();
return true;
}
// This method is required in iPhoneOS 3.0
public override void OnActivated (UIApplication application)
{
}
}
}
Let's run the application and make sure it works. From the menu in MonoDevelop, choose Run : Debug, or click the Apple Key and "Enter." You should see your home screen:
And if you click on the Web Browser button, the web browser screen should pop on:
Of course, it doesn't do anything yet, so let's code up our browser. Close the app in your simulator and open up WebBrowserView.xib.cs in MonoDevelop. Add the following method to your WebBrowserView class:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
//---- set the title
this.Title = "Browser";
//---- wire up event handlers
this.btnBack.TouchDown += HandleBtnBackhandleTouchDown;
this.btnForward.TouchDown += HandleBtnForwardhandleTouchDown;
this.btnStop.TouchDown += HandleBtnStophandleTouchDown;
this.btnGo.TouchDown += HandleBtnGohandleTouchDown;
this.txtAddress.ShouldReturn += HandleEditingDone;
this.webMain.LoadStarted += LoadStarted;
this.webMain.LoadFinished += LoadingFinished;
this.webMain.LoadError += LoadError;
//---- disable our buttons to start
this.btnBack.Enabled = false;
this.btnForward.Enabled = false;
this.btnStop.Enabled = false;
//---- navigate to google
this.txtAddress.Text = "google.com";
this.NavigateToUrl ();
}
The ViewDidLoad method runs after the view loads. The first thing we're doing here is setting the title of our page, which shows up in the Navigation bar at the top. Next, we wire up our event handlers to handle various events on the page and our web view. Next, we disable our buttons, since there is no browsing history yet (and we'll enable our stop button as soon as we start loading something). Finally, we set our start address to be google.com, and then we call our NavigateToUrl method, which we'll add next:
protected void NavigateToUrl ()
{
string url = this.txtAddress.Text;
//---- make sure it's prefixed with either https:// or http://
if (!(url.StartsWith ("http://") || url.StartsWith ("https://")))
{
url = "http://" + url;
}
this.webMain.LoadRequest (new NSUrlRequest (new NSUrl (url)));
}
This is a pretty simple method, we simply check to make sure the address starts with a valid http string, and then we tell our UIWebView control to load our URL.
Let's add one more method, then add all our event handlers:
protected void SetBackAndForwardEnable ()
{
this.btnBack.Enabled = this.webMain.CanGoBack;
this.btnForward.Enabled = this.webMain.CanGoForward;
}
This method is also pretty self-explanatory. We're simply enabling our back and forward buttons based on whether the Web View control has a forward or backwards history. It keeps track of that for us, so we don't have to. We'll call this method in our handlers.
Let's add our handlers. The first one is probably the trickiest and has nothing to do with the Web View:
protected bool HandleEditingDone (UITextField textBox)
{
textBox.ResignFirstResponder ();
NavigateToUrl ();
return true;
}
This is wired up to our txtAddress control, and is called when the user hits the "enter" button (which in our case is "Go," since we set it to that in Interface Builder). The ResignFirstResponder method hides the keyboard. We then call our
Let's add some more handlers:
The first handler, HandleBtnGohandleTouchDown simply loads the URL that is in the text box. The next handler tells the UIWebView to stop loading the request, when the user clicks the stop button. The last two handlers navigate forward or backward in the browser history, if they UIWebView allows it.
Let's add a couple more handlers:
These handlers run when the browser starts and finishes a request. We enable/disable our buttons, and animate our Busy Indicator as appropriate.
As you can see, the UIWebView control is super easy to work with. We've got one more handler to add, which is a really important one:
If you're publishing your application to the App Store, Apple will test your application both when the Internet is available, and when it isn't. If you don't handle not having Internet access gracefully by informing your user, your app is almost certain to get rejected.
In our case, we show a UIAlertView with the error information.
That's it! Your WebBrowserView.xib.cs file should now look like this:
Let's run it! Your web browser should now load up Google.com:
Or, if you don't have Internet access, you'll get the alert with the error:
As you can see, by utilizing the UIWebView control, it's incredibly easy to add a full-featured browser to your application. In the Part 2 of this article, I'll extend this application to allow it to utilize the UIWebView as a document viewer to browse local content.
protected void HandleBtnGohandleTouchDown (object sender, EventArgs e)
{
NavigateToUrl ();
}
protected void HandleBtnStophandleTouchDown (object sender, EventArgs e)
{
this.webMain.StopLoading ();
}
protected void HandleBtnForwardhandleTouchDown (object sender, EventArgs e)
{
if (this.webMain.CanGoForward)
{
this.webMain.GoForward ();
}
}
protected void HandleBtnBackhandleTouchDown (object sender, EventArgs e)
{
if (this.webMain.CanGoBack)
{
this.webMain.GoBack ();
}
}
public void LoadStarted (object source, EventArgs e)
{
this.btnStop.Enabled = true;
this.SetBackAndForwardEnable ();
this.imgBusy.StartAnimating ();
}
public void LoadingFinished (object source, EventArgs e)
{
this.SetBackAndForwardEnable ();
this.btnStop.Enabled = false;
this.imgBusy.StopAnimating ();
}
public void LoadError (object sender, UIWebErrorArgs e)
{
this.imgBusy.StopAnimating ();
this.btnStop.Enabled = false;
this.SetBackAndForwardEnable ();
//---- show the error
UIAlertView alert = new UIAlertView ("Browse Error"
, "Web page failed to load: " + e.Error.ToString ()
, null, "OK", null);
alert.Show ();
}
using System;
using System.Collections.Generic;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace Example_UIWebView
{
public partial class WebBrowserView : UIViewController
{
#region Constructors
// The IntPtr and initWithCoder constructors are required for controllers that need
// to be able to be created from a xib rather than from managed code
public WebBrowserView (IntPtr handle) : base(handle)
{
Initialize ();
}
[Export("initWithCoder:")]
public WebBrowserView (NSCoder coder) : base(coder)
{
Initialize ();
}
public WebBrowserView () : base("WebBrowserView", null)
{
Initialize ();
}
void Initialize ()
{
}
#endregion
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
//---- set the title
this.Title = "Browser";
//---- wire up event handlers
this.btnBack.TouchDown += HandleBtnBackhandleTouchDown;
this.btnForward.TouchDown += HandleBtnForwardhandleTouchDown;
this.btnStop.TouchDown += HandleBtnStophandleTouchDown;
this.btnGo.TouchDown += HandleBtnGohandleTouchDown;
this.txtAddress.ShouldReturn += HandleEditingDone;
this.webMain.LoadStarted += LoadStarted;
this.webMain.LoadFinished += LoadingFinished;
this.webMain.LoadError += LoadError;
//---- disable our buttons to start
this.btnBack.Enabled = false;
this.btnForward.Enabled = false;
this.btnStop.Enabled = false;
//---- navigate to google
this.txtAddress.Text = "google.com";
this.NavigateToUrl ();
}
protected void NavigateToUrl ()
{
string url = this.txtAddress.Text;
//---- make sure it's prefixed with either https:// or http://
if (!(url.StartsWith ("http://") || url.StartsWith ("https://")))
{
url = "http://" + url;
}
this.webMain.LoadRequest (new NSUrlRequest (new NSUrl (url)));
}
protected void SetBackAndForwardEnable ()
{
this.btnBack.Enabled = this.webMain.CanGoBack;
this.btnForward.Enabled = this.webMain.CanGoForward;
}
#region event handlers
protected bool HandleEditingDone (UITextField textBox)
{
textBox.ResignFirstResponder ();
NavigateToUrl ();
return true;
}
protected void HandleBtnGohandleTouchDown (object sender, EventArgs e)
{
NavigateToUrl ();
}
protected void HandleBtnStophandleTouchDown (object sender, EventArgs e)
{
this.webMain.StopLoading ();
}
protected void HandleBtnForwardhandleTouchDown (object sender, EventArgs e)
{
if (this.webMain.CanGoForward)
{
this.webMain.GoForward ();
}
}
protected void HandleBtnBackhandleTouchDown (object sender, EventArgs e)
{
if (this.webMain.CanGoBack)
{
this.webMain.GoBack ();
}
}
public void LoadStarted (object source, EventArgs e)
{
this.btnStop.Enabled = true;
this.SetBackAndForwardEnable ();
this.imgBusy.StartAnimating ();
}
public void LoadingFinished (object source, EventArgs e)
{
this.SetBackAndForwardEnable ();
this.btnStop.Enabled = false;
this.imgBusy.StopAnimating ();
}
public void LoadError (object sender, UIWebErrorArgs e)
{
this.imgBusy.StopAnimating ();
this.btnStop.Enabled = false;
this.SetBackAndForwardEnable ();
//---- show the error
UIAlertView alert = new UIAlertView ("Browse Error"
, "Web page failed to load: " + e.Error.ToString ()
, null, "OK", null);
alert.Show ();
}
#endregion
}
}



