3.2 在IB中使用视图和控制器
使用在第2章介绍过的IB,可以添加视图和控制器,然后以松耦合的方式将它们连接在一起,这个过程不需要编写或生成任何代码。如图3-2所示,从iPhone Window-based Project模板创建新的应用程序。这是一个带有窗口的基本应用程序,类似之前的AppDelegate。这里不在AppDelegate中完成所有工作,而是通过添加视图和控制器,在控制器中编写视图控制代码。
注意 就像第2章中看到的一样,MonoTouch会为outlet生成少量代码,类似于Objective-C的头文件。
MonoTouch包含一个带有控制器的iPhone(或iPad)视图模板,该控制器包含了一个带有预连接视图的xib文件。如图3-3所示,使用iPhone View with Controller模板创建一个名为SampleViewController的新文件。本示例的目标是通过模板在视图内创建UI,当应用程序加载时显示视图,并在相关控制器类内执行代码控制视图的显示。
现在,在IB中打开MainWindow.xib文件。因为不会直接在设计者视图上添加控件,所以可以关闭该视图。如图3-4所示,要添加新的UIViewController,可以将它拖到xib文件中。
现在要在SampleViewController.xib内设计视图并将它从xib加载。如图3-5所示,在MainWindow.xib窗口选择View Controller(视图控制器),然后在Attributes Inspector中修改NIB Name域的值为SampleViewController,这样就可以让IB知道要从SampleViewController.xib中加载控制器的视图。
另外,还要将UIViewController的类修改为SampleViewController,而不是它的基类UIViewController。如图3-6所示,要实现这个,在MainWindow.xib窗口中选择View Controller,然后在Identity Inspector中将Class域的值修改为SampleViewController,注意观察MainWindow.xib窗口中Type(类型)的变化。
为了在应用程序加载完毕后显示SampleViewController的视图,还需要从AppDelegate代码将控制器视图添加到窗口中,因为处理如FinishedLoading等应用程序生命周期的地方就是AppDelegate。因此,需要在AppDelegate内给SampleViewController添加outlet。回想一下,可以在IB的Library窗口的Classes标签页为类添加outlet。选择AppDelegate,添加一个名称为sampleVC的outlet,类型设置为SampleViewController。如图3-7所示,添加outlet后,就可以在MainWindow.xib的AppDelegate中将 outlet与SampleViewController连接起来。完成连接并保存文件后,MonoTouch会自动生成如代码清单3-1所示的包含outlet名称和类型的属性的代码。
提示 在MainWindow.xib窗口中右击AppDelegate,并拖动到MainWindow.xib窗口中的SampleViewController,将会弹出一个outlet可以连接的类型列表。
代码清单3-1 在AppDelegate中自动生成的SampleViewController属性
[MonoTouch.Foundation.Connect("sampleVC")]
private SampleViewController sampleVC {
get {
this.__mt_sampleVC =
((SampleViewController)(this.GetNativeField ("sampleVC")));
return this.__mt_sampleVC;
}
set {
this.__mt_sampleVC = value;
this.SetNativeField ("sampleVC", value);
}
}
现在,可以将SampleViewController的视图添加到窗口了,在AppDelegate的FinishedLaunching方法内添加以下代码:
public override bool FinishedLaunching (UIApplication app,
NSDictionary options)
{
window.AddSubview (sampleVC.View);
window.MakeKeyAndVisible ();
return true;
}
如果现在运行应用程序,SampleViewController.xib中的视图会显示,因为还没在视图内添加任何东西,所以显示的是一个空白屏幕。此时,可以对之前添加的SampleViewController.xib及其与它相关的控制器类进行处理了。
在IB中添加单个UITextView到SampleViewController的视图,它将在本章后面扩展后的示例中用做运行日志查看器。现在,简单添加一些文本来验证是否一切都已经正确连接起来。在IB中打开SampleViewController.xib并将UITextView拖到视图设计器,将它填满整个屏幕。选择文本视图,选择Attributes Inspector。清除示例文本,取消选择可编辑复选框,这样文本框就不能在运行时被用户更改了,它只能由代码更改。
与之前做的一样,为了能让程序修改文本视图,需要为它设置outlet。不过,这次outlet不是在AppDelegate中创建,而是在SampleViewController中创建。在SampleViewController.xib窗口中,可以看到File抯 Owner的类型是Sample-ViewController,该值表示当前xib文件的视图控制器是哪一个,当前情况下是SampleViewController。因此,任何添加到SampleViewController类的outlet和连接都会在SampleViewController类中创建一个属性,这样就可以通过代码访问它们了。类似于在AppDelegate中添加outlet一样,在SampleViewController类中为UITextView添加一个名为loggingView的outlet,然后将它连接到设计器中的UITextView(如图3-8所示)。
再重复一下,只要与outlet建立了连接,MonoDevelop就会自动生成相关属性,只有这次会在SampleViewController类中生成。在SampleViewController类内,重写ViewDidLoad方法,并添加以下代码修改文本视图的文本属性:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
loggingView.Text = "this is a test.";
}
现在运行应用程序,可以看到SampleViewController的视图已加载,而在视图内可看到如图3-9所示的由代码输出的字符串。
如果不想使用IB在MainWindow.xib文件中创建SampleViewController,也可以直接在代码中创建。要在MonoTouch中实现这个,只要直接在代码中简单实例化视图控制器的实例,并如之前那样将它的视图添加到窗口就可以了。因为控制器是视图的拥有者,而不是相反,所以对象图的根就是控制器。因此,采用该方法时,会看到这样一个警告:如果不为控制器保持一个类变量,它会被垃圾回收器回收。
要在代码中创建视图和控制器,可以跳过之前在MainWindow.xib窗口中所做的所有步骤,而在AppDelegate类中做以下修改。仍然可以在IB中设计SampleViewController的视图,唯一的变化是使用以下代码创建控制器:
SampleViewController _svc;
public override bool FinishedLaunching (UIApplication app,
NSDictionary options)
{
_svc = new SampleViewController ();
_svc.View.Frame = new RectangleF (0, 20,
UIScreen.MainScreen.Bounds.Width,
UIScreen.MainScreen.Bounds.Height - 20);
window.AddSubview (_svc.View);
window.MakeKeyAndVisible ();
return true;
}
现在,应用程序的设计是由UIViewController管理第一个视图的显示,而视图是在IB中进行设计的。SampleViewController及其视图也可以在代码中完成。在本章后面将演示如何通过代码控制视图。从现在开始,继续使用IB,以适应这种工具。
当为应用程序添加功能时,视图会变得越来越复杂,尤其是在需要控制器类在视图生命周期内捕获并处理附加子视图的事件时。此外,在应用程序中也可以有多个视图和控制器。不过,每一个视图都将由一个控制器进行管理,其基本结构与现在这个简单示例是一样的。
注意 有些控制器会专门设计成可以管理多个视图,如UITabBarController、UINavigationController或UITableViewController。UITabBarController将会在本章后面使用到,而UINavigationController和UITableViewController将会在第5章介绍。