iOS之更丰富的界面
2013-03-08 16:21 xioaxiao 阅读(272) 评论(0) 编辑 收藏 举报今天我们学习新的一章。本章将使用很多的控件,与实际的应用更相似。内容比较多,我们就分成几个部分。
一:
1) 创建应用程序。仍然是选择single view application。命名为Control Fun。
2) 这次,我们要将一个图像添加到项目之中。将想要添加的图像(图像不要太大,否则其它的控件就无法添加了)拖到工程里,在出现的对话框中,默认设置即可,确定。打开storyboard,从library中找到Image View,拖到view中,在Image View的四条边上有8个点,通过这几个点调节其与添加的图像差不多大小即可。
在attributes inspector中,找到image view中的image,在右侧的下拉菜单中,选择刚才添加到项目中的那幅图像的名称,这样图像就被添加到view中了。
双击图像,在editor菜单中,选择size to fit content,或者按快捷键command=,这样就调整了image view使它适应了所包含的内容。如图所示。
调整图像的个中属性。在attributes inspector中,会看到很多项。在这只说一下Apha,它是用来定义图像的透明度的。一般设为1.0。当该值小于1时,则iPhone回将此图绘制为透明的。即使图像后面没有任何内容,也会使应用程序花费处理周期来计算透明度。
由于图像视图使静态图像,并且也不会随着应用程序的运行发生改变,因此我们不需要outlet。
3) 在图像下添加两个Label(标签),分别更名为name和number,添加两个TextField(文本段)。修改第一个文本字段的属性,在attributes inspector中,在placeholder右边的文本框中输入Type in a name。这个placeholder的作用是用来指定在文本字段中以灰色显示的文本。在下面的capitalization中下拉列表中改为Words,此项将所有单词自动转换为首字母大写。在return key弹出项的值改为Done。其它文本输入特征保留为默认值。
再修改第二个文本字段的属性。再placeholder的文本框中输入Type in a Number。在keyboard 菜单中,选择number pad,因为这个文本段中,我们只希望输入数字。其它选项均为默认即可。
4) 编译运行下,看看结果。
5) 与我们设想的一样。但现在有个问题。按下Done按钮后,我们没有办法关掉键盘。因此,需要我们创建一个action,来关掉键盘。当用户按下Done按钮后,将产生一个Did End On Exit事件,此时我们需要让文本段取消控件,以关闭键盘。
为第一个TextField创建一个action,取名为textFeildDoneEditing,创建方法同上一节的一样。
- (IBAction)textFeildDoneEditing:(id)sender {
[sender resignFirstResponder];
}
意思是告诉触发此操作的控件,取消第一响应者状态。当文本字段失去第一响应者状态时,与之相关的键盘将消失。而何为第一响应者呢(FirstResponder)?简单来说就是用户当前正在与之交互的对象。运行下,发现这回好了。
6) 仔细观察会发现,这里还有一个问题,就是iPhone上,单击屏幕上的空白处即可关闭键盘,而现在我们需要返回到name文本段处按Done后才能关闭键盘。因此仍然需要我们来改进。通过触摸背景关闭键盘。
实现原理:
这是控件布局的树形图,我们所添加的项均是在这个view上。它充当着用户界面容器,它在用户界面没有外观,但涵盖了整个iPhone窗口。它的主要用途是持有其他视图和控件。该容器视图是我们的用户界面的背景。我们要做的是写一个Action,使这个View所携带的一个event能够调用这个Action。但这个view(或者称为root view)的类型是UIView,而UIView是没有event的,这样就无法和Action关联,因此我们需要将它的类型改为UIControl,它是UIView的子类,并且拥有event。更改完毕后,会发现,这个rootView名字自动改成了Control了。
现在,创建为两个textField各创建一个outlet,分别命名为nameField,numberField,并未这个rootControl创建一个事件,命名为backgroundTag。其中,event处选择Touch Down。之所以选择Touch Down,是因为后台不是一个按钮,我们希望点击屏幕任何的空白处都可以触发这个操作。点击connect。代码如下:
- (IBAction)backgroundTag:(id)sender {
[nameField resignFirstResponder];
[numberField resignFirstResponder];
}
7) 保存文件,编译运行,点击屏幕的任何位置,键盘都会取消,达到了我们想要的效果。
二:
下面我们继续学习,这部分主要学习slider控件。
1) 向view中添加一个slider控件.拖到view上,拉伸到合适的长度。
设置slider的属性。Value是取值范围,我们设为1-100;current为初始值,我们设为50。设置完成后,slider会根据设置自动调整。
2) 添加一个label。放到number下面,如图所示。同时选中这三个标签,Editor-Align-Right Edges或者command [使三者右对齐这其中有一点需要注意。50所在label的宽度一定要比50宽,因为我们设置的slider的最大值使100,如果label宽度不够的话,当其值变为100时,就会使部分数字看不见。
3) 这次label的值会随着slider的变化而变化,因此需要为label添加一个outlet,方法同以前一样,按住control,点击label,滑动到Control FunViewController.h中,在弹出的对话框中选择outlet,名字为sliderLabel,确认。为slider添加一个action,方法相似,命名为sliderChanged。
sliderChanged实现如下:
- (IBAction)sliderChanged:(id)sender {
UISlider *slider = (UISlider *) sender;
int progressAsInt = (int)(slider.value + 0.5);
NSString *newText = [[NSString alloc] initWithFormat:@"%d", progressAsInt];
sliderLabel.text = newText;
}
下面介绍下这个方法:首先将sender转换为UISider *,作用是避免每次使用sender时都要进行类型转换,使代码可读性更强。
接着接受滑块的值(int型),+0.5以便四舍五入为整型值。然后使用该整型值创建一个字符串,用于设置label的text(文本)。
4) 保存,运行代码。滑动slider,左边的值随着变化。
三:
这部分呢,主要是学习Segmented Control和Switch。
1) 首先将一个Segmented Control控件拖到view上,并宽展控件宽度,从视图左侧蓝色引导线到右侧引导线。双击First单词,改为Swtch。双击Second单词,改为Button。添加两个Switch,分别放在Segmented Control下方的两侧,靠近蓝色引导线。
2) 下面接着创建outlet和action。
为两个switch分别创建一个outlet,分别命名为leftSwitch和rightSwitch。为segmented创建一个action,命名为toggleControls,为switch创建一个action,命名为switchChanged,event处选择value changed,并将另一个switch关联到这个action上。
代码如下:
- (IBAction)switchChanged:(id)sender {
UISwitch *whichSwitch = (UISwitch *) sender;
BOOL setting = whichSwitch.isOn;
[leftSwitch setOn:setting animated:NO];
[rightSwitch setOn:setting animated:NO];
}
两个switch被关联在了同一个action,因此当有一个switch被按下后,该方法获取了sender的值,sender值只能等于leftSwitch或rightSwitch,并使有该值来设定两个开关。但在这个方法中,并没有确定实际是哪个开关别按下,只是简单的将两个开关设定成了相同的状态而已。
[leftSwitch setOn:setting animated:NO];
其中的animated,是用来指定按钮应该缓慢的滑动(YES)还是应该迅速的移动(NO)到新位置。 缓慢滑动给人的动画效果给用户的体验更好一些。
3) 在两个switch中间添加一个button按钮。拉伸,使其完全盖住两个switch。
双击,将其命名为DoSomething,在右边的attributes inspector中,选中Hidden复选框。现在button变成了透明状,但在真实的运行环境中,button会被隐藏。
4) 为button添加outlet和action。添加outlet是因为在点击segmented control时会控制它的隐藏或显示。outlet命名为doSomethingButton,action命名为buttonPressed。
首先在toggleControls键入代码如下:
- (IBAction)toggleControls:(id)sender {
if([sender selectedSegmentIndex] ==kSwitchesSegmentIndex){
leftSwitch.hidden =NO;
rightSwitch.hidden = NO;
doSomethingButton.hidden = YES;
}
else {
leftSwitch.hidden = YES;
rightSwitch.hidden = YES;
doSomethingButton.hidden = NO;
}
}
代码中引用了一个UISegmentedControl属性,即selectedSegmentIndex,它告诉我们当前选中的是哪一个分段(segmented control中块的index从左到右值依此为0,1…….)。kSwitchesSegentIndex是一个常量,值为零,让代码可读性更强。
当触发这个方法时,根据选定的分段控件,确定隐藏button或是switches。
运行程序,点击segmented control按钮,看看是否会隐藏相应的控件。
四:
1) 现在剩下最后一部分了,在这部分中,我们学习Action Sheet(操作表)和Alert(警告)。
Action Sheet:用于迫使用户在两个或更多项之间进行选择。从屏幕底部弹出,显示一系列按钮供用户选择。操作表通常用于确认潜在的危险或不能撤销的操作,比如删除一个对象。
Alert:以蓝色圆角巨型的形式出现在屏幕中央,迫使用户在继续使用应用程序前作出响应。警报更多地用于通知用户发生了一些重要的或者不正常的事,通常为单个按钮,但也可为多个。
这两项都应用了应用程序委托(delegate)。
应用程序委托:委托是一个对象周期性地向被指定为其委托的另一个对象发送消息,向其请求输入或者通知某件事情正在发生。该模式可替换类继承来对可复用对象的功能进行扩展。iOS中定义了很多方法,可供我们调用,但我们若想更改方法的一部分,如果通过继承来完成,这时候就需要继承一个很大的类,因此为了解决这个问题,就是用delegate来完成。但程序发现你改写了某个方法时,就会调用你的方法,而不是原来的方法。(其实,对于delegate我也很糊涂,上面这样说也不知道对不对,如果有那位朋友知道,希望你能告诉我,谢谢。)
2) 看看具体的实例。我们需要在实例中产生一个Action Sheet,为了让控制器类充当操作表的委托,控制器类需要遵从UIActionSheetDelegate(当然并不是所有的委托方法都需要我们实现,Alert 就不需要)
首先打开control funViewController.h文件,在类后面加上协议的名称
在buttonPressed中添加如下代码:
- (IBAction)buttonPressed:(id)sender {
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"Are you sure?" delegate:self cancelButtonTitle:@"No Way" destructiveButtonTitle:@"Yes, I'm Sure!" otherButtonTitles:nil];
[actionSheet showInView:self.view];
}
首先我们在buttonPressed操作方法中分配了一个UIActionSheet对象并进行了初始化,这个对象用于表示操作表。初始化方法接受了多个参数。第一个是操作表的标题,第二个是操作表的委托,它将在该表上的按钮被按下时受收到通知,它指明了这个actionSheet的delegate在哪里,self说明是在本类里。即在UIActionSheet所在的类中寻找UIActionSheet的代理方法的实现(这个例子中的类就是指类control funViewController,原因是<UIActionSheetDelegate>,让该类可以接收并响应UIActionSheet的委托事件)。
接着是操作表上的取消按钮,也就是不进行下一步的按钮,接着是确定按钮,如果还想在上面加一些其他按钮,可以上面otherButtonTitles:@“Foo”,@”Bar”,nil等,最后以nil表示结束。最后一行让它显示自己。每一个ActionSheet都需要有一个父视图,在父视图中显示自己,因为我们是单一视图项目(Single View),也只有一个View,因此这里的self.view就是说在actionSheet实现的这个view里显示。
3) 实现actionsheet的委托方法
在buttonPressed下面添加一个方法
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
if(buttonIndex != [actionSheet cancelButtonIndex]) {
NSString *msg = nil;
if(nameField.text.length > 0)
msg = [[NSString alloc] initWithFormat:@"You can breathe easy, %@,everything went OK.",nameField.text];
else
msg = [[NSString alloc] initWithFormat:@"You can breathe easy,everything went OK."];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Something was done" message:msg delegate:self cancelButtonTitle:@"Prew!" otherButtonTitles:nil];
[alert show];
}
}
这些代码实现了一个action sheet的delegate,当点击action sheet按钮时,回调用这个delegate。参数buttonIndex可以告诉我们实际按下的是哪个按钮。
如果用户在顶部的文本字段中输入了名字,我们将获取该值并在警报消息中使用它。
4) 编译运行,点击Yes,I’m sure,会出现一个alert,与我们料想的一样。
五:
本章终于结束了,内容好多,对于delegate这我还是不太明白,里面的很多东西都是参考网上的一些博客和书里的内容的。希望在以后慢慢会明白。