mono touch :Creating iOS Applications in Code

Creating iOS Applications in Code

This article examines how to create iOS applications entirely in code using Visual Studio. It shows how to start from an empty project template to build an application screen in a controller by creating a hierarchy of views from UIKit. Then, it discusses how to create custom views that can be loaded in a controller.

Overview

iOS user interfaces are built from a combination of views and controllers. Views are used to construct user interfaces in a hierarchical fashion. These view hierachies can be constructed in Xcode using Interface Builder to create Xib or Storyboards. Additionally, the Xamarin Studio designer can create Storyboard based user interfaces on OS X. However, in Visual Studio currently user interfaces can only be created in code. You do have the option of switching over to OS X just for the designer support though. Regardless, whether you wish to work exclusively in Visual Stduio, or you use designer from OS X, it is good to have a fundamental understanding of how to work entirely in code. This article walks through some basic points to get up and running with code-only user interface development.

Creating a Code-Only Project

iOS Empty Project Template

Let's create an iOS project in Visual Studio using the iPhone Empty Project template, shown below, which we'll extend to add controllers and views.

The Empty project template adds 3 files to the project:

  • AppDelegate.cs - Contains a UIApplicationDelegate subclass, AppDelegate, which is used to handle application events from iOS. The application window is created in the AppDelegate's FinishedLaunchingmethod.
  • Info.plist - Property list file that contains application configuration information.
  • Main.cs - Contains the entry point for the application, which specifies the class for the AppDelegate.

Creating a Window

iOS applications are built using the MVC pattern. The first screen that an application displays is created from the windows's root view controller. See the Multi-Screened Applications document for more details on the MVC pattern itself.

The implementation for the AppDelegate added by the template creates the application window, of which there is only one for every iOS application, and makes it visible with the following code:

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    // create a new window instance based on the screen size
    window = new UIWindow(UIScreen.MainScreen.Bounds);

    // make the window visible
    window.MakeKeyAndVisible();

    return true;
}

This produces a blank screen, as shown below in the simulator:

Adding a Controller

Let's add a controller to the window by creating a UIViewController instance and setting it to thewindow.RootViewController property:

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    // create a new window instance based on the screen size
    window = new UIWindow(UIScreen.MainScreen.Bounds);

    controller = new UIViewController();
    controller.View.BackgroundColor = UIColor.White;
    window.RootViewController = controller;

    // make the window visible
    window.MakeKeyAndVisible();

    return true;
}

Every controller has an associated view, which is accessible from the View property. The above code changes the view's BackgroundColor property to UIColor.White so that it will be visible, as shown below:

We could set any UIViewController subclass as the RootViewController in this way as well, including controllers from UIKit as well as those we write ourselves. For example, the following code adds aUINavigationController as the RootViewController:

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    // create a new window instance based on the screen size
    window = new UIWindow(UIScreen.MainScreen.Bounds);

    controller = new UIViewController();
    controller.View.BackgroundColor = UIColor.White;
    controller.Title = "My Controller";

    navController = new UINavigationController(controller);
    window.RootViewController = navController;

    // make the window visible
    window.MakeKeyAndVisible();

    return true;
}

This produces the controller nested within the navigation controller as shown below:

Creating a View Controller

Now that we've seen how to add a controller as the RootViewController of the window, let's see how to create a custom view controller in code.

Add a new class named CustomViewController as shown below:

The class should inherit from UIViewController, which is in the MonoTouch.UIKit namespace, as shown:

using System;
using MonoTouch.UIKit;

namespace CodeOnlyDemo
{
    class CustomViewController : UIViewController
    {
    }
}

Initializing the View

UIViewController has a method called ViewDidLoad that is called after the view is in memory. This is an appropriate place to do initialization of the view, such as setting it's properties.

For example, the following code changes the view's background color to gray:

using System;
using MonoTouch.UIKit;

namespace CodeOnlyDemo
{
    class CustomViewController : UIViewController
    {
        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            View.BackgroundColor = UIColor.Gray;
        }
    }
}

To load this controller, instantiate it and set it to the window's RootViewController in the AppDelegate as before:

controller = new CustomViewController();
window.RootViewController = controller;

Now when the application loads, the CustomViewController is loaded and its gray view is displayed:

Building the View Hierarchy

With a view controller created, we can now begin to create a user interface in code. iOS user interfaces are comprised of a view hierarchy. To add additional views, such as labels, buttons, sliders, etc. we add those views as subviews of some parent view.

For example let's make a login screen where the user can enter a username and password. The screen will consist of two text fields and a button.

Adding the Text Fields

First we'll add a control for the username by creating and initializing a UITextField and then adding it to the view hierarchy, as shown below:

class CustomViewController : UIViewController
{
    UITextField usernameField;

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();

        View.BackgroundColor = UIColor.Gray;

        float h = 31.0f;
        float w = View.Bounds.Width;

        usernameField = new UITextField
        {
            Placeholder = "Enter your username",
            BorderStyle = UITextBorderStyle.RoundedRect,
            Frame = new RectangleF(10, 10, w - 20, h)
        };

        View.AddSubview(usernameField);
    }
}

When we create the UITextField, we set the Frame property to define its location and size. In iOS the 0,0 coordinate is in the upper left with +x to the right and +y down. After setting the Frame along with a couple other properties, we call View.AddSubview to add the UITextField to the view hierarchy. This makes theusernameField a subview of the UIView instance that the View property references. A subview is added with a z-order that is higher than its parent view, so it appears in front of the parent view on the screen.

The application with the UITextField included is shown below:

We can add a UITextField for the password in a similar fashion, only this time we set the SecureTextEntryproperty to true, as shown below:

passwordField = new UITextField
{
    Placeholder = "Enter your pasword",
    BorderStyle = UITextBorderStyle.RoundedRect,
    Frame = new RectangleF(10, 45, w - 20, h),
    SecureTextEntry = true
};

View.AddSubview(passwordField);

Setting SecureTextEntry = true hides the text entered in the UITextField by the user as shown below:

Adding the Button

Next, we'll add a button so the user can submit the username and password. The button is added to the view hierarchy like any other control, by passing it as an argument to the parent view's AddSubview method again.

The following code adds the button and registers an event handler for the TouchUpInside event:

submitButton = UIButton.FromType(UIButtonType.RoundedRect);
submitButton.Frame = new RectangleF(10, 90, w - 20, 44);
submitButton.SetTitle("Submit", UIControlState.Normal);
submitButton.TouchUpInside += delegate
{
    Console.WriteLine("Submit button clicked");
};

View.AddSubview(submitButton);

With this in place the login screen now looks as shown below:

Handling Rotation

However, if the user rotates the device to landscape, the controls do not resize appropriately, as the following screenshot illustrates:

One way to fix this is by setting the AutoresizingMask property on each view. In this case we want the controls to stretch horizontally, so we would set each AutoresizingMask as:

AutoresizingMask = UIViewAutoresizing.FlexibleWidth

Now when we rotate the device or simulator, everything stretches to fill the additional space, as shown below:

Sizing for iPhone 5

Although the application will work fine on iPhone 5, it does not fill the entire screen when run in the iPhone 5 simulator or on a device, as illustrated below:

To fix this, we simply need to include a 640x1136 image named Default-568@2x.png. We can add this from the project properties in Visual Studio. Under the project properties, select iOS Application and scroll to theLaunch Images section:

Under Launch Images select the placeholder for the Retina Display (4-inch) image, and select a 640x1136 image in the Open dialog:

After selecting the image, its preview appears in the Launch Images section:

Also, it is added to the project under the Resources folder:

Now, when we run the app it fills the screen, as shown below:

Creating Custom Views

In addition to using controls that are part of UIKit, custom views can also be used. A custom view can be created by inheriting from UIView and overriding Draw. Let's create a custom view and add it to the view hierarchy to demonstrate.

Inheriting from UIView

The first thing we need to do is create a class for the custom view. We'll do this using the Class template in Visual Studio to add an empty class named CircleView. The base class should be set to UIView, which recall is in the MonoTouch.UIKit namespace. We'll also need the System.Drawing namespace as well. The other various System.* namespaces won't be used in this example, so feel free to remove them.

The class should look like this:

using System;
using System.Drawing;
using MonoTouch.UIKit;
using MonoTouch.CoreGraphics;

namespace CodeOnlyDemo
{
    class CircleView : UIView
    {
    }
}

Drawing in a UIView

Every UIView has a Draw method that is called by the system when it needs to be drawn. Draw should never be called directly. It is called by the system during run loop processing. The first time through the run loop after a view is added to the view hierarchy, its Draw method is called. Subsequent calls to Draw occur when the view is marked as needing to be drawn by calling either SetNeedsDisplay or SetNeedsDisplayInRect on the view.

We can add drawing code to our view by adding such code inside the overridden Draw method as shown below:

public override void Draw(RectangleF rect)
{
    base.Draw(rect);   

    //get graphics context
    using (CGContext g = UIGraphics.GetCurrentContext())
    {
        //set up drawing attributes 
        g.SetLineWidth(10);
        UIColor.Green.SetFill();
        UIColor.Blue.SetStroke();

        //create geometry 
        var path = new CGPath();
        path.AddArc(Bounds.GetMidX(), Bounds.GetMidY(), 50, 0, 2.0f * (float)Math.PI, true);

        //add geometry to graphics context and draw it
        g.AddPath(path);
        g.DrawPath(CGPathDrawingMode.FillStroke);
    }
}

Since CircleView is a UIView, we can also set UIView properties as well. For example, we can set theBackgroundColor in the constructor:

public CircleView()
{
    BackgroundColor = UIColor.White;
}

To use the CircleView we just created, we can either add it as a subview to the view hierarchy in an existing controller, like we did with the UILabels and UIButton earlier, or we can load it as the view of a new controller. Let's do the latter.

Loading a View

UIViewController has a method named LoadView that is called by the controller to create its view. This is an appropriate place to create a view and assign it to the controller's View property.

First, we need a controller, so create a new empty class named CircleController.

In CircleController add the following code to set the View to a CircleView:

using MonoTouch.UIKit;

namespace CodeOnlyDemo
{
    class CircleController : UIViewController
    {
        CircleView view;

        public override void LoadView()
        {
            base.LoadView();
            view = new CircleView();
            View = view;
        }
    }
}

Finally, we need to present the controller at runtime. Let's do this in the submit button that we added earlier as follows:

submitButton.TouchUpInside += delegate
{
    Console.WriteLine("Submit button clicked");

    //circleController is declared a s class variable
    circleController = new CircleController();
    PresentViewController(circleController, true, null);
};

Now, when we run the applicaiton and tap the submit button, the new view with a circle is displayed:

Summary

In this article we discussed how to develop iOS applications using Visual Studio entirely in code. We looked at how to build up a project from an empty project template, discussing how to create and add a root view controller to the window. We then showed how to use controls from UIKit to create a view hierarchy within a controller to develop an application screen. Next we examined how to make the views lay out appropriately in different orientations, as well as how to create a full screen application on iPhone 5. Finally, we saw how to create a custom view by subclassing UIView, as well as how to load the view within a controller.




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值