|
|
10 年之前 | |
|---|---|---|
| .. | ||
| Images | 10 年之前 | |
| ImagesVS | 10 年之前 | |
| readme.md | 10 年之前 | |
| readme_vs.md | 10 年之前 | |
In the Quickstart walkthrough, we built and ran our first Xamarin.iOS application. Now it’s time to develop a deeper understanding of how iOS applications work so we can build more sophisticated programs. In this guide we review the steps that we took in the Hello, iOS walkthrough so that we can understand what we did, and begin to develop a fundamental understanding of iOS application development.
We will explore the following topics:
This guide helps you develop the skills and knowledge required to build a single-screen iOS application. After working through it, you should have an understanding of the different parts of a Xamarin.iOS application and how they fit together.
Xamarin Studio is a free, open-source IDE that combines features from Visual Studio and XCode. It features a fully integrated visual designer, a text editor complete with refactoring tools, an assembly browser, source code integration, and more. In this guide we'll learn to use some basic Xamarin Studio features, but if you're new to Xamarin Studio you will want to check out the in-depth Introduction to Xamarin Studio.
Xamarin Studio follows the Visual Studio practice of organizing code into Solutions and Projects. A Solution is a container that can hold one or more Projects. A Project can be an application (such as iOS or Android), a supporting library, a test application, and more. In our Phoneword app, we created an empty Solution and added a new iPhone Project using the Single View Application template. Our initial Solution looked like this:
Let’s get oriented with our Solution’s contents. On the left is the Solution Pad, which contains the directory structure and all the files associated with our Solution:
We've created a Solution called Phoneword and placed our iOS Project - Phoneword_iOS - inside it. Let’s take a look at the items inside the Project:
AppDelegate .designer.cs is an auto-generated file that serves as the glue between controls in the View and their code representations in the View Controller. Because this is an internal plumbing file, the IDE will overwrite any manual changes and most of the time we can ignore this file. For more information on the relationship between the visual Designer and the backing code, refer to the Introduction to the iOS Designer guide.Info.plist is where we set application properties such as the application name, icons, launch images, and more. This is a powerful file and a thorough introduction to it is available in the Working with Property Lists guide.Entitlements.plist can be found in the Working with Property Lists guide. For a general introduction to entitlements, refer to the Device Provisioning guide.Now that we’ve developed a basic understanding of the components of a Xamarin.iOS application, let’s explore how the different parts work together to make the application run.
Before an iOS application can load a user interface, two things need to be in place. First, the application needs to define an entry point – the first code that runs when the application’s process is loaded into memory. Second, it needs to define a class to handle application-wide events and interact with the operating system.
In this section we’ll break down the relationships illustrated in the following diagram:
Let's start at the beginning and learn what happens at application startup.
The main entry point of an iOS application is the Main.cs file. Main.cs contains a static Main method that creates a new Xamarin.iOS application instance and passes the name of the Application Delegate class that will handle OS events. The template code for the static Main method appears below:
using System;
using UIKit;
namespace Phoneword_iOS
{
public class Application
{
static void Main (string[] args)
{
UIApplication.Main (args, null, "AppDelegate");
}
}
}
In iOS, the Application Delegate class handles system events; this class lives inside AppDelegate.cs. The AppDelegate class manages the application Window. The Window is a single instance of the UIWindow class that serves as a container for the user interface. By default, an application gets only one Window onto which to load its content, and the Window is attached to a Screen (single UIScreen instance) that provides the bounding rectangle matching the dimensions of the physical device screen.
The AppDelegate is also responsible for subscribing to system updates about important application events such as when the app finishes launching or when memory is low.
The template code for the AppDelegate is presented below:
using System;
using Foundation;
using UIKit;
namespace Phoneword_iOS
{
[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
public override UIWindow Window {
get;
set;
}
...
}
}
Once the application has defined its Window, it can begin loading the user interface. The next section explores UI creation.
The user interface of an iOS app is like a storefront - the application typically gets one Window, but it can fill the Window up with as many objects at it needs, and the objects and arrangements can be changed depending on what the app wants to display. The objects in this scenario - the things that the user sees - are called Views. To build a single screen in an application, Views are stacked on top of each other in a Content View Hierarchy, and the hierarchy is managed by a single View Controller. Applications with multiple screens have multiple Content View Hierarchies, each with its own View Controller, and the application places Views in the Window to create a different Content View Hierarchy based on the screen that the user is on.
In this section we dive into the user interface as we learn about Views, Content View Hierarchies, and the iOS Designer.
The iOS Designer is a visual tool for building user interfaces in Xamarin. We can launch the Designer by double-clicking on any Storyboard (.storyboard) file, which will open to a view that resembles the following screenshot:
A Storyboard is a file that contains the visual designs of our application’s screens as well as the transitions and relationships between the screens. The representation of an application’s screen in a Storyboard is called a Scene. Each Scene represents a View Controller and the stack of Views that it manages (Content View Hierarchy). When we create a new Single View Application Project from a template, Xamarin Studio automatically generates a Storyboard file called Main.storyboard and populates it with a single Scene, as illustrated by the screenshot below:
We can select the black bar at the bottom of the Storyboard screen to select the View Controller for the Scene. The View Controller is an instance of the UIViewController class that contains the backing code for the Content View Hierarchy. We can view and set properties on this View Controller inside the Properties Pad, as illustrated by the screenshot below:
If we click inside the white part of the Scene, we can select the View. The View is an instance of the UIView class that defines an area of the screen and provides interfaces for working with the content in that area. Our current View is a single Root View that fills the whole device screen:
To the left of the Scene is a gray arrow with a flag icon, as illustrated by the screenshot below:
The gray arrow represents a Storyboard transition called a Segue (pronounced “seg-way”). Since this Segue has no origin, it is called a Sourceless Segue. A Sourceless Segue points to the first Scene whose Views gets loaded into our application's Window at application startup. The Scene and the Views inside it will be the first thing that the user sees when the app loads.
When we build a user interface, we drag additional Views from the Toolbox onto the main View on the design surface, as illustrated by the screenshot below:
These additional Views are called Subviews. Together, the root View and Subviews are part of a Content View Hierarchy that is managed by our ViewController. We can see the outline of all the elements in the Scene by examining it in the Document Outline pad:
The Subviews are highlighted in the diagram below:
Let’s break down the Content View Hierarchy represented by this Scene in the next section.
A Content View Hierarchy is a stack of Views and Subviews managed by a single View Controller, as illustrated by the diagram below:
We can make the Content View Hierarchy of our ViewController easier to see by temporarily changing the background color of the root View to yellow in the View section of the Properties Pad, as illustrated by the screenshot below:
The diagram below illustrates the relationships between the Window, Views, Subviews, and View Controller that bring the user interface to the device screen:
In the next section, we will discuss how to work with Views in code and learn to program for user interaction using View Controllers and the View Lifecycle.
Every Content View Hierarchy has a corresponding View Controller to power user interaction. The role of the View Controller is to manage the Views in the Content View Hierarchy. The View Controller is not part of the Content View Hierarchy, and it's not an element in the interface. Rather, it provides the code that powers the user's interactions with the objects on the screen.
The View Controller is represented in a Storyboard as a black bar at the bottom of the Scene. Selecting the View Controller brings up its properties in the Properties Pad:
We can specify a custom View Controller class for the Content View Hierarchy represented by this Scene by editing the Class property in the Identity section of the Properties Pad. For example, our Phoneword application sets the ViewController as the View Controller for our first screen, as illustrated by the screenshot below:
This links the Storyboard representation of the View Controller to the ViewController C# class. If we open the ViewController.cs file, we see that our View Controller is a subclass of UIViewController, as illustrated by the code below:
public partial class ViewController : UIViewController
{
public ViewController (IntPtr handle) : base (handle)
{
}
}
The ViewController now drives the interactions of the Content View Hierarchy associated with this View Controller in the Storyboard. Next we’ll learn about the View Controller's role in managing the Views by introducing a process called the View lifecycle.
UIViewController, which is appropriate if we don’t plan on adding custom code.The View Controller is in charge of loading and unloading Content View Hierarchies from the Window. When something of importance happens to a View in the Content View Hierarchy, the operating system notifies the View Controller through events in the View lifecycle. By overriding methods in the View lifecycle, we can interact with the objects on the screen and create a dynamic, responsive user interface.
These are the basic lifecycle methods and their function:
When we add custom code to any stage of the Lifecycle, we override that Lifecycle method’s base implementation. We tap into the existing Lifecycle method, which has some code already attached to it, and we extend it with our own code. We call the base implementation from inside our method to make sure the original code runs before our new code. We’ll see an example of this in the next section.
For more information on working with View Controllers, refer to Apple's View Controller Programming Guide for iOS and the UIViewController reference.
The most important role of the View Controller is responding to user interaction, such as button presses, navigation, and more. The simplest way to handle user interaction is to wire up a control to listen to user input and attach an event handler to respond to the input. For example, we could wire up a button to respond to a touch event, like we did in our Phoneword app.
Now that we have a deeper understanding of Views and View Controllers, let's explore how this works.
In our Phoneword_iOS Project, we added a button called TranslateButton to our Content View Hierarchy:
When we assigned a Name to the Button control in the Properties Pad, the iOS designer automatically mapped it to a control in the ViewController.designer.cs, making the TranslateButton available to us inside the ViewController class. We know that controls first become available in the ViewDidLoad stage of the View Lifecycle, so we prepared to respond to the user's touch inside the lifecycle method:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// wire up TranslateButton here
}
In our Phoneword app, we used a touch event called TouchUpInside to listen to the user's touch. TouchUpInside listens for a touch up event (finger lifting off the screen) that follows a touch down (finger touching the screen) inside the bounds of the control. The opposite of TouchUpInside is the TouchDown event, which fires when the user presses down on a control. The TouchDown event captures a lot of noise and gives the user no option to cancel the touch by sliding their finger off the control. TouchUpInside is the most common way to respond to a Button touch and creates the experience the user expects when pressing a button. More information on this is available in Apple’s iOS Human Interface Guidelines.
In our app we handled the TouchUpInside event with a lambda, but we could have also used a delegate or a named event handler. Our final Button code resembled the following:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
string translatedNumber = "";
TranslateButton.TouchUpInside += (object sender, EventArgs e) => {
translatedNumber = Core.PhonewordTranslator.ToNumber(PhoneNumberText.Text);
PhoneNumberText.ResignFirstResponder ();
if (translatedNumber == "") {
CallButton.SetTitle ("Call", UIControlState.Normal);
CallButton.Enabled = false;
} else {
CallButton.SetTitle ("Call " + translatedNumber, UIControlState.Normal);
CallButton.Enabled = true;
}
};
}
The Phoneword application introduced several concepts not covered in this guide. These concepts include:
SetTitle on the Button and passing in the new text and the Button’s Control State. For example, the following code changes the CallButton’s text to “Call”:
CallButton.SetTitle ("Call", UIControlState.Normal);
Enabled or Disabled state. A disabled Button won’t respond to user input. For example, the following code disables the CallButton:
CallButton.Enabled = false;
For more information on buttons, refer to the Buttons guide.
TranslateButton to dismiss the keyboard when the user presses the TranslateButton:
PhoneNumberText.ResignFirstResponder ();
For another example of dismissing the keyboard, refer to the Dismiss the Keyboard recipe.
var url = new NSUrl ("tel:" + translatedNumber);
if (!UIApplication.SharedApplication.OpenUrl (url))
{
// show alert Controller
}
if (!UIApplication.SharedApplication.OpenUrl (url)) {
var alert = UIAlertController.Create ("Not supported", "Scheme 'tel:' is not supported on this device", UIAlertControllerStyle.Alert);
alert.AddAction (UIAlertAction.Create ("Ok", UIAlertActionStyle.Default, null));
PresentViewController (alert, true, null);
}
For more information on iOS alert views, refer to the Alert Controller recipe.
Both Xamarin Studio and Visual Studio provide many options for testing and deploying an application. This section covers debugging options, demonstrates testing applications on device, and introduces tools for creating custom app icons and launch images.
Sometimes issues in application code are difficult to diagnose. To help diagnose complex code issues, we could Set a Breakpoint, Step Through Code, or Output Information to the Log Window.
The iOS Simulator is a quick way to test an application. The Simulator has a number of useful optimizations for testing, including mock location, simulating movement, and more. However, users will not consume the final app in a Simulator. We should test applications on real devices early and often.
A device takes time to provision and requires an Apple Developer Account. The Device Provisioning guide gives thorough instructions on getting a device ready for development.
Once the device is provisioned, we can deploy to it by plugging it in, changing the target in the build toolbar to iOS Device, and pressing Start ( Play) as illustrated by the following screenshot:
The app will deploy to our iOS device:
Not everyone has a designer available to create the custom icons and launch images an app needs to stand out. Here are several alternate approaches to generating custom app artwork:
For more information about icon and launch image sizes and requirements, refer to the Working with Images guide.
Congratulations! You now have a solid understanding of the components of a Xamarin.iOS application as well as the tools used to create them. In the next tutorial in the Getting Started series, we’ll extend our application to handle multiple screens. Along the way we’ll implement a Navigation Controller, learn about Storyboard Segues, and introduce the Model, View, Controller (MVC) pattern as we extend our application to handle multiple screens.