第2章 UI控件

第2章 UI控件

学习目标

图片 782

  • 掌握什么是UIView及UIView提供的常见属性和方法。

  • 掌握常见UI控件的使用,能够灵活使用控件开发iOS应用。

一个用户体验良好的应用,都离不开友好的图形用户界面。iOS应用开发的一项重要内容就是用户界面的开发,iOS提供了大量功能丰富的UI控件,开发者只要按一定规律将这些UI控件组合起来,就可以开发出优美的图形用户界面。本章将针对iOS中的UI控件进行详细讲解。

2.1 UIView概述

2.1.1 什么是UIView

在iOS开发中,每个UI控件都相当于一个个小的积木,这些控件都继承了UIView。曾经有人这么说过,在iPhone中,你看到的、摸到的都是UIView,例如,按钮、图片、文字等。既然UIView是所有控件的父控件,那么它必定拥有很多子控件,接下来,通过一张图来描述UIView的继承体系结构,如图2-1所示。

绘图1

图2-1 UIView继承体系图

从图2-1中可以看出,UIView继承体系中的类具有不同的层次关系,例如,UIView继承自UIResponder,它提供了许多子类,如UILabel、UITabBar、UIPickerView、UIControl等。其中,UIControl类又提供了子类 UIButton、UITextField、UITextView等。通常情况下,继承UIView的子类对象也称为视图。

为了便于大家更好地理解这些类,接下来,通过一个应用程序界面来讲解这些类的具体应用,如图2-2所示。

图片1

图2-2 应用程序界面

从图2-2中可以看出,应用程序的界面都是由一个一个的控件组成的,这些控件对应的是不同的类,这些类在后面的章节中都会进行详细讲解,这里大家有个大致印象即可。

2.1.2 UIView的常见属性和方法

在开发iOS程序时,经常需要修改UI控件的显示状态,例如,文件下载的进度条是实时更新的,论坛访问人数也是实时变化的,这些UI控件状态的修改,其实就是通过修改UI控件属性实现的。虽然不同的UI控件都有自己独特的属性,但某些属性是每个UI控件都具备的。UIView提供了许多公共的属性,例如,每个UI控件都有自己的位置和尺寸,每个UI控件都有父控件、子控件。接下来,通过一张表来列举UIView的常见属性,见表2-1。

表2-1 UIView的常见属性

属性声明

功能描述

@property(nonatomic,readonly) UIView *superview;

用于获得自己的父控件对象

@property(nonatomic,readonly,copy)NSArray *subviews;

用于获取自己所有的子控件对象

@property(nonatomic) CGAffineTransform transform;

用于表示控件的形变属性(可以设置旋转角度、比例缩放、平移等属性)

@property(nonatomic) NSInteger tag;

用于表示控件的ID(标识),父控件可以通过tag来找到对应的子控件

@property(nonatomic) CGRect frame;

控件所在矩形框在父控件中的位置和尺寸(以父控件的左上角为坐标原点)

@property(nonatomic) CGRect bounds;

用于表示控件所在矩形框的位置和尺寸(以自己左上角为坐标原点)

@property(nonatomic) CGPoint center;

控件中点的位置(以父控件的左上角为坐标原点)

@property(nonatomic) CGFloat alpha;

用于控制控件的透明度,其值支持0.0~1.0的任意浮点数值

表2-1列举了UIView的常见属性,其中,bounds属性是以自己左上角为坐标原点定义控件所在矩形框的位置和尺寸,因此,它可以实现控件大小的定义;center属性则是以父控件的左上角为坐标原点定义控件中点的位置,它可以实现控件位置的定义;而tag属性则可以定义控件的唯一标识,用于程序获取该控件的引用。

除此之外,UIView还提供了许多常见的方法,见表2-2。

表2-2 UIView的常见方法

方法声明

功能描述

- (void)addSubview:(UIView *)view;

用于添加一个子控件view

- (void)removeFromSuperview;

用于从父控件中移除

- (UIView *)viewWithTag:(NSInteger)tag;

根据控件的tag标识找出对应的控件

表2-2列举了UIView的3个常见方法,其中,addSubview方法用于向当前视图添加一个子视图,并将该子视图的保留计数加1;removeFromSuperview方法会从父视图中移除当前视图,并将当前视图的保留计数减1;为了方便查找控件,通常情况下,我们都会为每个控件添加一个Tag,如果想根据Tag查找对应的控件,则可以使用viewWithTag方法来实现。

图像说明文字 脚下留心:UIKit坐标系

在实际开发中,经常需要对视图进行各种变换,例如,缩放、平移、旋转等。而在进行这些操作之前,都需要明确当前视图的位置和尺寸,而这些数值都与UIKit坐标系有关。接下来,通过一张图来描述UIKit是如何定义坐标系的,如图2-3所示。

未命名:Users:gaomeiyun:Desktop:坐标系.png

图2-3 UIKit坐标系

从图2-3中可以看出,UIKit坐标系中的原点位于左上角,横坐标正方向水平向右延伸,纵坐标正方向竖直向下延伸,并且图中所示的iPhone的分辨率大小为320×480。

2.2 标签控件和图片控件

UIView提供了许多子类,这些子类分别代表不同的控件。在众多的控件中,有些控件几乎在每个应用程序中都会用到,例如,用于文本显示的标签控件、用于展示图片的图片控件,接下来,本节将针对这两个最简单的控件进行详细讲解。

2.2.1 标签控件(UILabel)

在iOS开发中,控件标签是使用UILabel类表示的,它直接继承自UIView类,是一个用于显示文字的静态控件。默认情况下,标签控件是不能接受用户输入,也不能与用户交互的。为了大家更好地理解什么是标签控件,接下来,通过一张图来描述标签控件的应用场景,如图2-4所示。

图像说明文字

图2-4 标签控件的应用

图2-4所示是一个用户注册的界面,该图中使用了多个标签控件用于显示固定的文字。由此可见,标签控件的使用是非常频繁的。

要想在程序中使用标签控件,首先得学会创建标签控件。创建标签控件最简单的方式就是将对象库中的Label控件直接拖曳到Main.storyboard编辑界面中,如图2-5所示。

11111

图2-5 将Label控件拖曳到程序界面

从图2-5中可以看出,使用拖曳控件的方式可以轻而易举地完成Label控件的创建,这时,选中Label控件,在Xcode右侧会出现UILabel的属性检查器面板,用于对Label控件进行设置,如图2-6所示。

图片 87

图2-6 UILabel的属性检查器面板

图2-6所示标识出了UILabel控件的一些属性设置,这些属性设置均可改变UILabel控件的显示状态。同时,针对属性检查器面板中的设置,UILabel还提供了相应的属性,接下来,通过一张表来列举UILabel控件的常见属性,见表2-3。

表2-3 UILabel的常见属性

属性声明

功能描述

@property(nonatomic,copy) NSString*text;

设置显示的文本内容,默认为nil

@property(nonatomic,retain) UIFont*font;

设置字体和字体大小,默认为系统字体17号

@property(nonatomic,retain) UIColor *textColor;

设置文本的颜色,默认为黑色

@property(nonatomic,retain) UIColor*shadowColor;

设置文本的阴影色彩和透明度,默认为nil

@property(nonatomic)CGSize shadowOffset;

设置阴影纵横向的偏移量,默认为CGSizeMake(0, -1),即为顶部阴影

@property(nonatomic) NSTextAlignment textAlignment;

设置文本在标签内部的对齐方式,默认为NSTextAlignmentLeft,即为左对齐

@property(nonatomic) NSLineBreakMode lineBreakMode;

指定换行模式,模式为枚举类型

@property(nonatomic) NSInteger numberOfLines;

指定文本行数,为0时没有最大行数限制

表2-3列举了UILabel控件的常见属性,其中text属性支持两种文本设置方式,分别是Plain和Attributed;font属性用于设置UILabel显示的字体样式及大小;shadowOffset用于设置控件内的阴影文本与正常文本之间的偏移,该属性需要指定Horizontal和Vertical两个值,分别表示阴影文本与正常文本在水平和垂直方向的偏移距离。

为了大家更好地掌握标签控件的属性,接下来,创建一个Single View Application应用,命名为01_UILabel,进入viewController.m文件,通过纯粹的代码方式来创建一个标签控件,并且使用UILabel提供的属性对标签进行设置,代码如例2-1所示。

【例2-1】ViewController.m

1  #import "ViewController.h"
2  @interface ViewController ()
3  @end
4  @implementation ViewController
5  -(void)viewDidLoad {
6    [super viewDidLoad];
7    // 1.初始化标签控件
8    UILabel *label = [[UILabel alloc] init];
9    // 2.设置标签控件的frame
10    CGFloat labelX = 0; // X值为0
11    CGFloat labelY = 210; // Y值为210
12    CGFloat labelW = self.view.bounds.size.width; //width值为屏幕宽度
13    CGFloat labelH = 120; // height值为40
14    CGRect frame = CGRectMake(labelX, labelY, labelW, labelH);
15    label.frame = frame;
16    // 3.设置背景颜色为灰色
17    label.backgroundColor = [UIColor lightGrayColor];
18    // 4.设置字体和字体颜色
19    label.text = @"Welcome to itcast传智播客";
20    label.font = [UIFont fontWithName:@"Helvetica-Bold" size:40];
21    label.textColor = [UIColor whiteColor];
22    // 5.设置对齐方式为居中
23    label.textAlignment = NSTextAlignmentCenter;
24    // 6.设置阴影
25    label.shadowColor = [UIColor colorWithWhite:0.1f alpha:0.8f];
26    label.shadowOffset = CGSizeMake(2, 3);
27    // 7.设置换行
28    label.lineBreakMode = NSLineBreakByWordWrapping;
29    label.numberOfLines = 2;
30    // 显示到UIView
31    [self.view addSubview:label];
32   }
33  @end

程序的运行结果如图2-7所示。

在例2-1中,创建标签控件和设置属性的具体代码都是在viewDidLoad方法中实现的。这是因为程序的视图控制器完成视图的加载后,会自动调用viewDidLoad方法对子控件views进行进一步的初始化。从图2-7中可以看出,程序成功创建了一个特定样式的标签控件。

2.2.2 图片控件(UIImageView)

友好的用户界面,离不开丰富的图片。图片控件是用UIImageView类表示的,它直接继承于UIView类,是一个用于显示图片的静态控件。例如,应用程序的下载界面,包含了多个图片控件,如图2-8所示。

图片 88

图2-7 运行结果

image208

图2-8 应用下载界面

图2-8所示是一个应用程序下载的界面,该界面包含了多个图片控件,这些图片控件都只有展示的功能,并不能实现与用户的交互功能。

要想在程序中使用UIImageView显示图片,最简单的方式也是直接将对象库中的Image View拖曳到程序界面中。当选中该控件后,在Xcode右侧会出现UIImageView的属性检查器面板,该面板用于修改UIImageView的显示状态,如图2-9所示。

说明: 未命名:Users:wangxiaojuan:Downloads:UIImage.jpg

图2-9 UIImageView的属性检查器面板

在图2-9显示的UIImageView属性器面板中,其中,Mode属性是继承自UIView的,该属性可以控制UIImageView显示图片的缩放模式,单击该属性的下拉列表,如图2-10所示。

图片 24

图2-10 Mode属性列表框

从图2-10所示,Mode属性包含了很多选项,这些选项所代表的含义如下所示。

  • Scale To Fill:不保持纵横比缩放图片,使图片完全适应该UIImageView控件。
  • Aspect Fit:保持纵横比缩放图片,使图片的长边能完全显示,即可以完整地展示图片。
  • Aspect Fill:保持纵横比缩放图片,只能保证图片的短边能完成显示出来,即图片只能在水平或者垂直方向是完整的,另一个方向会发生截取。
  • Center:不缩放图片,只显示图片的中间区域。
  • Top:不缩放图片,只显示图片的顶部区域。
  • Bottom:不缩放图片,只显示图片的底部区域。
  • Left:不缩放图片,只显示图片的左边区域。
  • Right:不缩放图片,只显示图片的右边区域。
  • Top Left:不缩放图片,只显示图片的左上边区域。
  • Top Right:不缩放图片,只显示图片的右上边区域。
  • Bottom Left:不缩放图片,只显示图片的左下边区域。
  • Bottom Right:不缩放图片,只显示图片的右下边区域。

针对UIImageView属性检查器面板中的设置,UIImageView类也定义了相应的属性,接下来,通过一张表来列举UIImageView的常见属性,见表2-4。

表2-4 UIImageView的常见属性

属性声明

功能描述

@property(nonatomic,retain) UIImage *image;

访问或设置控件显示的图片

@property(nonatomic,retain) UIImage *highlightedImage;

设置高亮状态下显示的图片

@property(nonatomic,getter=isUserInteractionEnabled) BOOL userInteractionEnabled;

设置是否允许用户交互,默认不允许用户交互

@property(nonatomic,getter=isHighlighted) BOOL highlighted;

设置是否高亮状态,默认为普通状态

@property(nonatomic,copy) NSArray *animationImages;

设置序列帧动画的图片数组

@property(nonatomic,copy) NSArray *highlightedAnimationImages;

设置高亮状态下序列帧动画的图片数组

@property(nonatomic) NSTimeInterval animationDuration;

设置序列帧动画播放的时长

@property(nonatomic) NSInteger animationRepeatCount;

设置序列帧动画播放的次数

表2-4列举了UIImageView常见的属性,其中,前4个属性是用来设置图片状态的,后4个属性是用来设置图片动画的。这些属性都是操作UIImageView最常用到的,在后面的小节中,将针对这些属性的使用进行详细讲解。

由于UIImageView可以实现序列帧动画显示一组图片,因此,UIImageView除了提供实现动画的相关属性外,还提供了实现序列帧动画的相关方法,接下来,通过一张表来列举UIImageView关于序列帧动画播放的相关方法,见表2-5。

表2-5 UIImageView用于播放帧动画的相关方法

方法声明

功能描述

- (void)startAnimating;

开始播放动画

- (void)stopAnimating;

停止播放动画

- (BOOL)isAnimating;

判断是否正在播放动画

表2-5中列举了3个方法,这3个方法都是用来控制动画播放状态的。

2.2.3 实战演练——会喝牛奶的汤姆猫

相信大家都知道一个比较好玩的应用叫“会说话的汤姆猫”,该应用中的汤姆猫不仅可以模仿人说话,还可以指挥汤姆猫进行各种动作,如喝牛奶、挠抓屏幕、挨打等动作。其实,这些动作都是一系列图片的动画效果,接下来,我们以喝牛奶为例,带领大家使用图片控件来开发一个会喝牛奶的汤姆猫,具体步骤如下。

1.创建工程,设计界面

(1) 新建一个Single View Application应用,名称为02_UIImageView,然后在Main.storyboard界面中添加一个UIImageView控件和一个UIButton控件,其中,UIImageView控件用于显示汤姆猫,UIButton控件用于显示牛奶瓶。

(2) 将提前准备好的图片分别放到Supporting Files和Images.xcassets文件中,并为
UIImageView控件和UIButton控件设置背景图片,设计好的界面如图2-11所示。

无标题

图2-11 喝牛奶的汤姆猫界面

2.创建控件对象的关联

(1)单击Xcode 6.1界面右上角的图片 92图标,进入控件与代码的关联界面,选中UIButton控件,添加一个单击事件,命名为drink,如图2-12所示。

图片 93

图2-12 创建UIButton控件对象的关联

(2)同样的方式,选中UIImageView控件,添加一个表示汤姆猫的对象,命名为tom,如图2-13所示。

图片 94

图2-13 创建UIImageView对象的关联

3. 通过代码实现汤姆猫喝牛奶的功能

完成控件对象的关联后,就可以通过代码实现汤姆猫喝牛奶的功能了。进入ViewController.m文件,在drink方法中加载图片,并且设置喝牛奶的一系列动画,代码如例2-2所示。

【例2-2】ViewController.m

1  #import"ViewController.h"
2  @interface ViewController ()
3  // 声明一个表示汤姆猫的属性tom
4  @property (weak, nonatomic) IBOutlet UIImageView *tom;
5  // 声明一个喝牛奶的方法drink
6  -(IBAction)drink:(id)sender;
7  @end
8  @implementation ViewController
9  -(IBAction)drink:(id)sender {
10    // 1.加载所有的动画图片
11    NSMutableArray *images=[NSMutableArray array];
12    for(int i=0;i<81;i++){
13      // 计算文件名
14      NSString *filename=[NSString stringWithFormat:@"drink_%02d.jpg",i];
15      // 加载图片
16      UIImage *image=[UIImage imageNamed:filename];
17      // 添加图片到数组中
18      [images addObject:image];
19  }
20    self.tom.animationImages=images;
21    //2.设置播放次数(1次)
22    self.tom.animationRepeatCount=1;
23    // 3.设置播放时间
24    self.tom.animationDuration=8;
25    // 4.开始播放动画
26    [self.tom startAnimating];
27  }
28  @end

在例2-2中,第11行代码创建了一个数组,用于存放一系列动画图片;第12~18行代码用于将存放在指定目录下的图片添加到数组中;第20行代码用于设置动画图片;第22~24行代码用于设置动画播放的次数及其持续时间;第26行代码用于播放动画。

4. 在模拟器上运行程序

单击Xcode工具的运行按钮,在模拟器上运行程序。程序运行成功后,单击喝牛奶的图标,一个“会喝牛奶的汤姆猫”应用成功开发完成了。汤姆猫喝牛奶的部分场景如图2-14所示。

图像说明文字

图2-14 会喝牛奶的汤姆猫

注意:

PNG格式的图片资源,可以直接放到Images.xcassets文件和Supporting Files文件下;而 JPEG格式的图片资源只能放到Supporting Files文件下。

2.3 按钮控件(UIButton)

2.3.1 按钮控件概述

按钮控件是最常用的控件之一,通常情况下,单击某个控件后,会做出相应反应的都是按钮控件。在iOS开发中,按钮控件使用UIButton类表示的,它直接继承自UIControl:UIView,是一个既能显示文字,又能显示图片,还能随时调整内部图片和文字位置的按钮。例如,播放器界面有很多按钮控件,如图2-15所示。

2222

图2-15 播放器界面中的按钮

图2-15所示的是播放器界面中的一部分,这部分包含了5个按钮控件,这些控件都是可单击的,并且单击这些按钮控件后,会做出不同的反应。

同标签控件、图片控件一样,创建按钮控件最简单的方式也是通过拖曳控件的方式来完成。进入对象库,选中Button控件,在Xcode右侧会出现UIButton的属性检查器面板,如图2-16所示。

UIButton

图2-16 UIButton的属性检查器面板

图2-16所示的是UIButton所支持的一些属性,其中,Type和State Config属性比较难理解,接下来,针对这两个属性进行详细讲解,具体如下。

1. Type

该属性用于设置按钮的类型,它支持多个选项,单击Type下拉列表,如图2-17所示。

4444

图2-17 按钮控件的Type属性

从图2-17中可以看出,按钮控件的Type属性有6个选项,这6个选项表示的含义如下所示。

  • Custom:该选项表示按钮控件是开发者自己定义的,是最常被选用的Type类型。
  • System:该选项是iOS默认的按钮风格。
  • Detail Disclosure:该按钮通常用于显示当前列表项的详情,最新发布的iOS 8中显示图片 29图标。
  • Info Light:显示图片 30图标的图形按钮,该按钮通常用于显示简短的说明信息。
  • Info Dark:显示图片 31图标的图形按钮,该按钮通常用于显示简短的说明信息。
  • Add Contact:显示图片 32图标的图形按钮,该按钮通常用于显示添加联系人。

2.State Config

该属性用于配置该按钮的状态,它支持多个选项,单击State Config下拉列表,如图2-18所示。

5555

图2-18 按钮控件的State Config属性

从图2-18中可以看出,按钮控件的State Config属性有4个选项,这4个选项表示的含义如下所示。

  • Default:这是按钮默认的状态。
  • Highlighted:当用户触碰该按钮时,该按钮显示高亮状态。
  • Selected:表示按钮被选中的状态。
  • Disabled:表示按钮被禁用后的状态。

针对UIButton属性检查器面板中的设置,UIButton类也定义了相应的属性,接下来,通过一张表来列举UIButton的常见属性,见表2-6。

表2-6 UIButton类的常见属性

属性声明

功能描述

@property(nonatomic,readonly) UIButtonType buttonType;

用于设置按钮控件的类型

@property(nonatomic,readonly,retain) UILabel *titleLabel;

用于设置按钮控件显示的文本

@property(nonatomic,readonly,retain) UIImageView*imageView;

用于显示按钮控件的图片

除此之外,UIButton类还提供了许多可以设置UIButton外观的方法,这些方法都比较常用。表2-7列举了UIButton提供的常见方法。

表2-7 UIButton类的常见方法

方法声明

功能描述

- (void)setTitle:(NSString *)title forState:(UIControlState)state;

用于设置按钮的文本和状态

- (void)setTitleColor:(UIColor *)color forState:(UIControlState)state;

用于设置按钮的标题颜色和状态

- (void)setBackgroundImage:(UIImage *)image forState:(UIControlState)state;

用于设置按钮的背景图片和状态

- (void)setImage:(UIImage *)image forState:(UIControlState)state;

用于设置按钮的图片和状态

表2-7列举的方法中都需要指定一个forState参数,该参数是一个UIControlState整数值,用于接收UIControlStateNormal、UIControlStateHighlighted、UIControlStateDisabled、UIControlStateSelected状态的值,这4个状态所代表的值刚好是图2-18所列出的4种状态。

2.3.2 实战演练——使用按钮移动、旋转、缩放图片

UIButton作为iOS开发中最常用的控件之一,它主要用于响应用户在界面中触发的事件。为了帮助大家熟练掌握UIButton的使用,接下来,带领大家使用按钮控件来控制图片的移动、旋转和缩放,具体步骤如下。

1.创建工程,设计界面

(1)新建一个Single View Application应用,名称为03_UIButton,然后在Main.storyboard界面中添加1个UIImageView控件和8个UIButton控件,其中,UIImageView控件用于显示要操作的图片,UIButton控件用于控制图片的上下左右移动、左右旋转和放大缩小。

(2)将提前准备好的图片放到Supporting Files文件中,并为UIImageView控件和UIButton控件设置背景图片。设计好的界面如图2-19所示。

图片 34

图2-19 按钮操作图片的界面

在图2-19中,上移、下移、左移、右移的操作分别和图中箭头的方向对应,左旋、右旋和放大、缩小也一样。需要注意的是,为了区分移动、旋转、缩放的不同按钮,我们需要为每个按钮设置一个Tag属性,这里,我们为上移、下移、左移、右移、左旋转、右旋转、放大、缩小设置的Tag属性为1、2、3、4、5、6、7、8。

2.创建控件对象的关联

(1)单击Xcode 6.1界面右上角的图片 35图标,进入控件与代码的关联界面,为具备移动操作的4个UIButton控件添加同一个单击事件,命名为run,如图2-20所示。

图片 36

图2-20 创建移动按钮对象的关联

(2)同样的方式,为旋转按钮、缩放按钮添加相应的事件,分别命名为rotate和scale,为UIImageView添加属性,命名为img,添加完成后的界面如图2-21所示。

图片 37

图2-21 完成控件对象关联后的界面

从图2-21中可以看出,完成控件对象的关联后,在ViewController.m文件中会自动生成控件对象对应属性和方法的声明。

3. 通过代码实现图片的移动、旋转、缩放功能

完成控件对象的关联后,就可以通过代码实现按钮移动、旋转、缩放图片的功能了。进入ViewController.m文件,通过代码对不同的方法进行实现,代码如例2-3所示。

【例2-3】ViewController.m

1  #import "ViewController.h"
2  @interface ViewController ()
3  // 声明一个表示图片的属性img
4  @property (weak, nonatomic) IBOutlet UIImageView *img;
5  - (IBAction)scale:(id)sender; // 声明缩放图片的方法
6  - (IBAction)rotate:(id)sender;// 声明旋转图片的方法
7  - (IBAction)run:(id)sender;  // 声明移动图片的方法
8  @end
9  @implementation ViewController
10  - (void)viewDidLoad {
11   [super viewDidLoad];
12  }
13  // 用于缩放图片的方法
14  - (IBAction)scale:(id)sender {
15    // 获取图片的transform属性
16    CGAffineTransformt=self.img.transform;
17    // 获取图片的tag属性
18    NSInteger tag = [sender tag];
19    if (tag==7) {
20      CGAffineTransform temtransform =CGAffineTransformScale(t, 1.2,1.2);
21      self.img.transform= temtransform;
22    }else{
23      CGAffineTransform temtransform=CGAffineTransformScale(t, 0.8,0.8);
24      self.img.transform=temtransform;
25   }
26  }
27  // 用于旋转图片的方法
28  - (IBAction)rotate:(id)sender {
29   // 获取图片的transform属性
30   CGAffineTransform temtransform=self.img.transform;
31   // 获取按钮的tag属性
32   NSInteger rotatetag=[sender tag];
33     if (rotatetag==5) {
34     self.img.transform=CGAffineTransformRotate(temtransform,M_PI_4 * -1);
35   }else{
36     self.img.transform = CGAffineTransformRotate(temtransform,M_PI_4 * 1);
37   }
38  }
39  // 用于移动图片的方法
40  - (IBAction)run:(id)sender {
41   // 获取图片的frame属性
42   CGRect tmpframe = self.img.frame;
43   // 获取按钮的tag属性
44   NSInteger runtag=[sender tag];
45   switch (runtag) {
46     case 1: // 向上移动
47       tmpframe.origin.y-=10;
48       self.img.frame=tmpframe;
49       break;
50     case 2: // 向下移动
51       tmpframe.origin.y+=10;
52       self.img.frame=tmpframe;
53       break;
54     case 3: // 向左移动
55       tmpframe.origin.x-=10;
56       self.img.frame=tmpframe;
57       break;
58     case 4: // 向右移动
59       tmpframe.origin.x+=10;
60       self.img.frame=tmpframe;
61       break;
62     default:
63       break;
64   }
65  }
66  @end

在例2-3中,使用按钮对图片进行各种操作时,首先都是获取图片对象的相关属性,然后根据图片对象的Tag属性,执行不同的动作。以run方法为例,该方法用于实现图片的移动操作,第41~44行代码分别获取了图片的frame和按钮的tag属性,第45~65行代码使用switch语句,根据按钮的tag属性,判断按钮移动的方向,并对frame属性的坐标位置进行修改,从而实现图片的移动。

4. 在模拟器上运行程序

单击Xcode工具的运行按钮,在模拟器上运行程序。程序运行成功后,单击不同的按钮操作图片,发现图片可以实现移动、旋转和缩放了。使用按钮对图片进行移动、旋转、缩放后的部分图片如图2-22所示。

图像说明文字

图2-22 使用按钮移动、旋转、缩放图片

2.4 文本框控件和文本控件

在iOS开发中,经常需要一些显示文字的控件,虽然UILabel标签可以实现文字的展示,但它不能和用户进行交互,为此,UIKit框架提供了UITextField和UITextView文本控件,接下来,本节将针对这两个控件进行详细讲解。

2.4.1 文本框控件(UITextField)

在iOS开发中,文本框控件使用UITextField来表示,它和UIButton控件一样,都直接继承自UIControl控件,并且可以和用户进行交互。为了帮助大家更好地理解什么是文本框控件,接下来,通过新浪微博登录的界面来展示UITextField的使用场景,如图2-23所示。

4

图2-23 新浪微博登录界面

图2-23所示的是一个新浪微博的登录界面,该界面中的用户名和密码输入框都是使用文本框控件UITextField控件实现的。由此可见,UITextField控件不仅可以显示,同时可供用户输入或者编辑文本。

要想在程序中使用UITextField,首先得学会创建UITextField。同样从对象库中找到Text Field,将其拖曳到Main.storyboard编辑界面中,这样就轻而易举地创建了一个文本输入框。选中Text Field控件,Xcode右侧出现了UITextField的属性检查器面板,该面板用于设置UITextField的相关属性,如图2-24所示。

说明: 未命名:Users:wangxiaojuan:Downloads:1.png

图2-24 UITextField的属性检测器面板

图2-24所示的是UITextField所支持的一些属性,通过设置这些属性,可以使文本框的状态发生相应变化。接下来,针对Clear Button属性和Keyboard Type属性进行详细讲解。

1. Clear Button

Clear Button用于控制何时显示清除按钮,选中文本框控件,单击该属性的下拉列表,结果如图2-25所示。

说明: 未命名:Users:wangxiaojuan:Desktop:截图.jpg

图2-25 Clear Button属性支持的选项

图2-25所示的是UITextField控件的Clear Button属性选项,这些选项所代表的含义如下所示。

  • Never appears:从不显示清除按钮。
  • Appears while editing:当编辑内容时显示清除按钮。
  • Appears unless editing:除了编辑之外,都会显示清除按钮。
  • Is always visible:清除按钮一直可见。

2 .Keyboard Type

Keyboard Type用于设置文本框关联的键盘类型,选中文本框控件,单击该属性的下拉列表,结果如图2-26所示。

图片 40

图2-26 Keyboard Type属性支持的选项

图2-26所示的是Keyboard Type属性所支持的选项,这些选项所代表的含义如下所示。

  • Default:显示默认的虚拟键盘。
  • ASCII Capable:显示英文字母键盘。
  • Numbers and Punctuation:显示数字和标点符号键盘。
  • Number Pad:显示数字键盘。
  • Phone Pad:显示电话拨号键盘。
  • E-mail Address:显示输入E-mail地址的虚拟键盘。
  • Decimal Pad:显示可输入数字和小数点的虚拟键盘。

针对UITextField属性检查器面板设置的属性,UITextField类也定义了与之对应的属性,接下来通过一张表来列举UITextField的常见属性,见表2-8。

表2-8 UITextField的常见属性

属性声明

功能描述

@property(nonatomic)UIControlContentVerticalAlignment contentVerticalAlignment;

设置文本框内文本的垂直对齐方式

@property(nonatomic,copy)NSString *placeholder;

设置文本框未输入文本时的提示信息

@property(nonatomic)UITextBorderStyle borderStyle;

设置文本框边框的样式

@property(nonatomic) UITextFieldViewModeclearButtonMode;

设置文本框是否显示清除按钮

@property(nonatomic,getter=isSecureTextEntry) BOOL secureTextEntry;

设置文本框输入的字符是否密文显示

@property(nonatomic) UITextAutocorrectionType autocorrectionType;

设置是否自动更正文本框内的文本内容

@property(nonatomic)BOOL clearsOnBeginEditing;

再次编辑时是否清空之前的文本内容

@property(nonatomic)BOOL adjustsFontSizeToFitWidth;

设置文本内容是否适应文本框窗口大小

@property(nonatomic) UITextAutocapitalizationType autocapitalizationType;

设置文本框内文本内容首字母是否为大写

@property(nonatomic,readonly,getter=isEditing) BOOL editing;

设置文本框内文本内容是否允许编辑

@property(nonatomic,assign) id<UITextFieldDelegate> delegate;

设置代理

@property(nonatomic) UIKeyboardType keyboardType;

设置文本框关联的键盘类型

@property(nonatomic) UIKeyboardAppearance keyboardAppearance;

设置文本框关联键盘的外观样式

@property(nonatomic) UIReturnKeyType returnKeyType;

设置文本框关联键盘的回车键类型

@property(nonatomic,retain) UIView *leftView;

设置文本框左侧视图

@property(nonatomic) UITextFieldViewMode leftViewMode;

设置文本框左视图的显示方式

@property(nonatomic,retain) UIView *rightView;

设置文本框右侧视图

@property(nonatomic) UITextFieldViewMode rightViewMode;

设置文本框右视图的显示方式

表2-8列举出了UITextField的常见属性,其中delegate为代理属性,如果一个对象要想监听文本框的动态,如限制文本框输入内容的个数,该对象可以成为文本框的代理来实现监听,但是前提是要遵守UITextFieldDelegate协议,该协议的定义方式如下所示。

@protocol UITextFieldDelegate <NSObject>
@optional
// 文本框是否可以进入编辑模式(是否可进入输入状态)
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField;
// 文本框进入编辑模式
- (void)textFieldDidBeginEditing:(UITextField *)textField;
// 是否退出编辑模式(是否可结束输入状态)
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField;
//退出编辑模式(结束输入状态)
- (void)textFieldDidEndEditing:(UITextField *)textField;
// 当输入任何字符时,代理调用该方法
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:
(NSRange)range replacementString:(NSString *)string;
// 是否可以单击清除按钮
- (BOOL)textFieldShouldClear:(UITextField *)textField;
// 单击键盘上的return按钮时调用
- (BOOL)textFieldShouldReturn:(UITextField *)textField;
@end

从上述代码中可以看出,UITextFieldDelegate协议中定义了许多供代理监听的方法,这些方法会在文本框的不同状态下被调用。例如,textFieldShouldReturn方法是单击键盘上的return键按钮时调用的方法,该方法可以实现单击return键后所执行的行为。

2.4.2 实战演练——用户登录“传智播客”

UITextField作为用户输入文本的控件之一,它经常会运用在一些用户的登录界面,例如,新浪微博的登录界面,用户名和密码的文本输入框就是使用UITextField实现的。为了帮助大家更好地学习UITextField的使用,接下来,带领大家开发一个用户登录传智播客的案例,具体步骤如下。

1.创建工程,设计界面

(1)新建一个Single View Application应用,名称为04_UITextField,然后在Main.storyboard界面中添加一个UIImageView控件、两个UITextField控件和一个UIButton控件,其中,UIImageView控件用于显示Logo图片,UITextField控件用于输入用户登录的用户名和密码,UIButton控件用于用户的登录。

(2)将提前准备好的图片放到Supporting Files文件中,并为UIImageView控件和UIButton控件设置背景图片。为了确保密码的安全,通常情况下,我们都会将密码设置为密文显示,即用于输入密码的UITextField控件中的Secure Text Entry属性勾选上。设计好的界面如图2-27所示。

图片 41

图2-27 用户登录的界面

2.创建控件对象的关联

(1)单击Xcode 6.1界面右上角的图片 42图标,进入控件与代码的关联界面,为UITextField控件添加用于表示用户名和密码的属性,分别命名username和password,创建好的界面如图2-28所示。

图片 116

图2-28 为UITextField控件添加属性

(2)同样的方式,为登录按钮添加一个事件,命名为login,添加完成后的界面如图2-29所示。

图片 117

图2-29 为UIButton控件添加用于单击的方法

3. 通过代码实现用户登录的功能

完成控件对象的关联后,就可以通过代码实现用户登录的功能了。为了演示用户登录的功能,我们假设有一个用户名为itcast,密码为12345的用户。使用代码实现用户登录功能的代码如例2-4所示。

【例2-4】viewController.m

1  #import "ViewController.h"
2  @interface ViewController ()
3  -(IBAction)login:(id)sender;// 用于声明UIButton按钮的单击事件
4  // 用于声明两个UITextField控件所对应的属性
5  @property (weak, nonatomic) IBOutlet UITextField *password;
6  @property (weak, nonatomic) IBOutlet UITextField *username;
7  @end
8  @implementation ViewController
9  - (void)viewDidLoad {
10    [superviewDidLoad];
11  }
12  -(IBAction)login:(id)sender {
13    // 获取用户名
14    NSString *username=self.username.text;
15    // 获取密码
16    NSString *password=self.password.text;
17    // 判断用户名和密码是否正确
18    if ([username isEqualToString:@""]||[password isEqualToString:@""]) {
19      [self showMessage:@"用户名或密码不能为空"];
20     }elseif(![password isEqualToString:@"12345"]||
21    ![username isEqualToString:@"itcast"]){
22       [self showMessage:@"用户名或密码错误"];
23     }elseif([username isEqualToString:@"itcast"]&&
24      [password isEqualToString:@"12345"]){
25       [self showMessage:@"登录成功"];
26      }
27   }
28  // 提示信息的方法
29  -(void)showMessage:(NSString *) message{
30    UIAlertView *alert=[[UIAlertView alloc] initWithTitle:nil message:
31               message delegate:nil cancelButtonTitle:@"确定" 
32               otherButtonTitles:nil,nil];
33    [alert show];
34  }
35  @end

在例2-4中,第18~26行代码用于对用户名和密码进行判断,并且调用了showMessage方法显示登录的结果,showMessage方法是程序第29~34行代码定义的一个方法,该方法首先创建了一个UIAlertView对象,并在创建该对象时指定了警告框的标题、消息内容及警告框包含的按钮信息,然后调用show方法,将创建的UIAlertView对象显示出来。

4. 在模拟器上运行程序

单击Xcode工具的运行按钮,在模拟器上运行程序。程序运行成功后,在文本框中输入用户名和密码,单击登录按钮,这时,不管用户名和密码输入的是否正确,都会弹出一个对应的提示框,效果如图2-30所示。

图像说明文字

图2-30 用户登录的运行结果

2.4.3 多行文本控件(UITextView)

在iOS应用中,经常需要输入多行文本,这时,需要使用UITextView控件实现。与UITextField控件相比,UITextView继承自UIScrollView:UIView类,它不仅可以输入并显示文本,而且可以在固定的区域展示足够多的文本,并且这些文本内容可以换行显示。为了帮助大家更好地理解什么是UITextView,接下来,通过一张发表微博的图片来展示UITextView的应用场景,如图2-31所示。

图片 81

图2-31 UITextView的使用场景

图2-31所示是发送微博的界面,其中,发表微博内容的区域是一个可以滚动显示的文本框,它是由一个多行文本控件实现的。通常情况下,多行文本控件也称为文本视图。

同样,在学习UITextView控件之前,先来看一下UITextView控件所支持的属性。从对象库中将Text View直接拖曳到Main.storyboard编辑界面并选中,在Xcode右侧会出现了UITextView的属性检查器面板,如图2-32所示。

image276

图2-32 UITextView的属性检测器面板

图2-32所示标识出了UITextView常见属性的设置,这些属性所代表的含义比较简单,大家可以通过修改属性的设置,体会这些属性对UITextView所起的作用。

除了可以在属性检查器面板中设置属性外,还可以使用UITextView类提供的属性来进行设置,接下来,通过一张表来列举UITextView的常见属性,具体如表2-9所示。

表2-9 UITextView的常见属性

属性声明

功能描述

@property(nonatomic,assign) id<UITextViewDelegate> delegate;

设置代理

@property(nonatomic,getter=isEditable) BOOL editable;

设置文本视图是否可编辑

@property(nonatomic,getter=isSelectable) BOOL selectable;

设置文本视图是否可选择

@property(nonatomic) BOOL clearsOnInsertion;

设置文本视图输入时是否清除之前的文本

@property(nonatomic,copy) NSAttributedString *attributedText;

设置文本视图默认插入的文字内容

@property (readwrite, retain) UIView *inputView;

设置底部弹出的视图

@property (readwrite, retain) UIView *inputAccessory View;

设置底部弹出视图上方的辅助视图

@property(nonatomic) UIViewAutoresizing autoresizingMask;

设置文本视图自动适应高度

表2-9列举了UITextView的常见属性,其中delegate为代理属性,文本视图的事件交由代理对象处理,实现对文本视图的监听,但是前提要遵守UITextViewDelegate协议,该协议的定义方式如下所示。

@protocol UITextViewDelegate <NSObject, UIScrollViewDelegate>
@optional
// 用户将要开始编辑UITextView的内容时会激发该方法
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView;
// 用户开始编辑该UITextView的内容时会激发该方法
- (void)textViewDidBeginEditing:(UITextView *)textView;
// 用户将要结束编辑该UITextView的内容时会激发该方法
- (BOOL)textViewShouldEndEditing:(UITextView *)textView;
//用户结束编辑该UITextView的内容时会激发该方法
- (void)textViewDidEndEditing:(UITextView *)textView;
// 该UITextView内指定范围内的文本内容将要被替换时激发该方法
- (BOOL)textView:(UITextView *)textView 
shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
// 该UITextView中包含的文本内容发生改变时会激发该方法
- (void)textViewDidChange:(UITextView *)textView;
// 用户选中该UITextView内某些文本时会激发该方法
- (void)textViewDidChangeSelection:(UITextView *)textView;
@end

从上述代码中可以看出,UITextViewDelegate协议中定义了很多方法,这些方法会在不同的状态下被激发。例如,textView:shouldChangeTextInRange:方法是替换多行文本控件中指定文本时会触发的方法,该方法可以实现把回车键当作退出键盘的响应键。

2.5 开关控件(UISwitch)

2.5.1 开关控件概述

在某些iOS应用中,经常会看到一些类似传统物理开关的控件,例如,手电筒的开关、Setting选项中的定位开关等,这些开关都是使用开关控件UISwitch实现的,为了大家更好地理解什么是开关控件,接下来,通过一张图来描述开关控件的应用场景,如图2-33所示。

image278

图2-33 Setting选项中的Safari选项

图2-33所示的是一个Setting选项中的Safari选项界面,该界面中包含了很多UISwitch控件,并且这些控件都只有“开/关”两种状态。

UISwitch控件继承自UIControl类,它是一个可以与用户进行交互的控件。同样,在学习UISwitch控件之前,先来看一下UISwitch所支持的属性。将对象库中的UISwitch控件拖曳到Main.storyboard编辑界面并选中,Xcode右侧会出现UISwitch的属性检查器面板,如图2-34所示。

image280

图2-34 UISwitch控件的属性检查器面板

从图2-34中可以看出,UISwitch控件属性检查器面板中的属性比较少,其中,State属性用于切换开关控件的“开/关”状态,应用程序可以通过属性on或方法isOn来检测当前的状态。

2.5.2 实战演练——使用开关控制“灯泡”

在iPhone或iPad设备上,经常会看到类似于手电筒这种应用,它的界面比较简单,只有一个开关控制手电筒的打开关闭状态,出于这种设计思路,接下来,我们使用开关控件UISwitch来控制“灯泡”,当用户打开UISwitch时,应用程序界面的灯泡图片是点亮的,当用户关闭UISwitch控件时,灯泡的图片是熄灭的,具体步骤如下。

1.创建工程,设计界面

(1)新建一个Single View Application应用,名称为05_UISwitch,然后在Main.storyboard界面中添加一个UIImageView控件和一个UISwitch控件,其中,UIImageView控件用于显示灯泡的图片,UISwitch控件用于显示开关。

(2)将提前准备好的图片放到Supporting Files文件中,并将UISwitch控件的初始状态设置为打开,UIImageView控件的初始图片是灯泡点亮的状态,设计好的界面如图2-35所示。

图片 504

图2-35 使用开关控制灯泡的界面

2.创建控件对象的关联

单击Xcode 6.1界面右上角的图片 57图标,进入控件与代码的关联界面,为UIImageView控件添加表示图片对象的属性,命名为img;同理,为UISwitch控件添加切换开关状态的方法,命名为change,添加完成后的界面如图2-36所示。

图片 124

图2-36 为控件对象添加关联

3. 通过代码实现灯泡开关的控制

完成控件对象的关联后,就可以通过代码实现灯泡开关的控制了。进入ViewController.m文件,在change方法中,首先判断灯泡切换时的状态,然后根据灯泡开关的状态对灯泡的图片进行切换。使用开关控制灯泡的代码如例2-5所示。

【例2-5】viewController.m

1 #import "ViewController.h"
2 @interface ViewController ()
3 -(IBAction)change:(id)sender;
4 @property (weak, nonatomic) IBOutlet UIImageView *img;
5 @end
6 @implementation ViewController
7 - (void)viewDidLoad {
8     [super viewDidLoad];
9 }
10 - (IBAction)change:(id)sender {
11 if(![sender isOn]){
12        // 获取文件的名称
13        NSString *filename=[NSString stringWithFormat:@"img_01.jpg"];
14        // 加载图片
15        UIImage *image=[UIImage imageNamed:filename];
16         // 更换图片
17         self.img.image=image;
18     }else {
19        // 获取文件的名称
20        NSString *filename=[NSStringstringWithFormat:@"img_02.jpg"];
21        // 加载图片
22        UIImage *image=[UIImageimageNamed:filename];
23        // 更换图片
24        self.img.image=image;
25    }
26 }
27 @end

在例2-5中,change方法是控制灯泡开关的核心代码,当程序通过调用isOn方法后,如果判断的结果不是YES,则说明控制灯泡的开关是关闭状态,这时,将当前界面的图片使用img_02替换。同理,如果开关是打开状态,则将当前页面的图片替换为img_01。

4. 在模拟器上运行程序

单击Xcode工具的运行按钮,在模拟器上运行程序。程序运行成功后,单击开关按钮,发现使用开关可以控制灯泡,效果如图2-37所示。

2.6 滑块控件(UISlider)

2.6.1 滑块控件概述

在播放器界面,经常可以看到类似于进度条的控件,例如,音量的控制、播放进度的控制。在iOS开发中,这种使用滑块来改变数值的控件称为滑块控件。滑块控件使用UISlider表示,它继承自UIControl,是一个可以与用户进行交互的控件。接下来,通过一张音乐播放的图片来展示UISlider的应用场景,如图2-38所示。

图像说明文字

图2-37 使用开关控制灯泡的运行结果

图片 127

图2-38 音乐播放器界面

图2-38所示的是一个音乐播放器的界面,该播放器中的歌曲播放进度就是一个滑块控件,它可以通过拖动的方式来改变音乐的播放进度。

同学习其他控件一样,从对象库中将滑块控件拖曳到Main.storyboard编辑界面中并选中,在 Xcode右侧查看UISlider的属性检查器面板中的相关属性,如图2-39所示。

图片 128

图2-39 UISlider的属性检查器面板

图2-39展示了UISlider支持的一些属性,这些属性都可以改变UISlider的状态。同时,针对UISlider属性检查器面板设置的属性,UISlider类也定义了与之对应的属性,接下来通过一张表来列举UISlider的常见属性,见表2-10。

表2-10 UISlider的常见属性

属性声明

功能描述

@property(nonatomic) float value;

设置或者获取滑块的值

@property(nonatomic) float minimumValue;

设置滑块的最小值,默认为0.0

@property(nonatomic) float maximumValue;

设置滑块的最大值,默认为1.0

@property(nonatomic,retain) UIImage *minimumValueImage;

设置滑块最小值边界的图片

@property(nonatomic,retain) UIImage *maximumValueImage;

设置滑块最大值边界的图片

@property(nonatomic,retain) UIColor *minimumTrackTintColor;

设置小于滑块当前值的轨道颜色,默认为蓝色

@property(nonatomic,retain) UIColor *maximumTrackTintColor;

设置大于滑块当前值的轨道颜色,默认为白色

@property(nonatomic,retain) UIColor *thumbTintColor;

设置当前拖动条的颜色,默认为白色

表2-10列举出了UISlider常见的一些属性,它们都可以改变滑块的样式。同时UISlider类还提供了相应的方法,用来定制滑块的外观,接下来通过一张表来列举UISlider的常见方法,见表2-11。

表2-11 UISlider的常见方法

方法声明

功能描述

- (void)setThumbImage:(UIImage *)image forState:(UIControlState)state;

设置滑块上拖动条的图片

- (void)setMinimumTrackImage:(UIImage *)image forState:(UIControlState)state;

设置滑块已完成进度的轨道图片

- (void)setMaximumTrackImage:(UIImage *)image forState:(UIControlState)state;

设置滑块未完成进度的轨道图片

表2-11列举出了UISlider常见的一些方法,这些方法都需要传入UIImage对象,使用图片来改变UISlider的外观。

2.6.2 实战演练——使用滑块控制音量

在大多数应用中,音量的控制都是通过滑块控件实现的。为了帮助大家更好地学习滑块控件UISlider的使用,接下来,我们来模拟实现一个控制音量的功能,具体步骤如下:

1.创建工程,设计界面

(1)新建一个Single View Application应用,名称为06_UISlider,然后在Main.storyboard界面中添加一个UISlider控件、一个UILabel控件和一个UIImageView控件,其中UIImageView用于显示图片,UILabel用于提示用户拖动滑块,UISlider用于根据不同的阶段的值切换图片。

(2)将UISlider控件的Current属性设置为0.4,UILabel控件的text属性设置为“提示:请拖动滑块改变音量”。

(3)将提前准备好的图片资源放到Supporting Files文件中,为UIImageView设置默认显示的图片,设计好的界面如图2-40所示。

图片 542

图2-40 使用滑块控制音量的界面

2.创建控件对象的关联

单击Xcode 6.1界面右上角的图片 129图标,进入控件与代码的关联界面,选中UIImageView,添加一个表示音量的对象,命名为voiceImageV,同样,为UISlider控件添加一个表示音量控制的滑块对象,命名为slider,添加完成后的界面如图2-41所示。

图片 130

图2-41 创建控件对象关联后的界面

3. 通过代码实现调节音量的功能

完成控件对象的关联后,就可以通过代码实现调节音量的功能了。进入ViewController.m文件,根据滑块数值的变化适时地切换音量图片,代码如例2-6所示。

【例2-6】ViewController.m

1  #import "ViewController.h"
2  @interface ViewController ()
3  // 滑块
4  @property (weak, nonatomic) IBOutlet UISlider *slider;
5  // 音量图片
6  @property (weak, nonatomic) IBOutlet UIImageView *voiceImageV;
7  @end
8  @implementation ViewController
9  - (void)viewDidLoad {
10    // 1.为滑块控件UISlider添加监听器
11    [self.slider addTarget:self action:@selector(valueChange:) 
12    forControlEvents:UIControlEventValueChanged];
13  }
14  // 滑块数值发生变化时会调用的方法
15  - (void)valueChange:(UISlider *)slider0
16  {
17    // 1.设置图片的数量
18    int count = 4;
19    // 2.获取滑块的值
20    float level = slider0.value;
21    // 3.根据滑块的值适时切换图片
22    if (level>=0 && level<1.0/(count-1)) {
23      self.voiceImageV.image = [UIImage imageNamed:@"voice0.jpg"];
24    }else if (level>=1.0/(count-1) && level<2.0/(count-1)){
25      self.voiceImageV.image = [UIImage imageNamed:@"voice1.jpg"];
26    }else if(level>=2.0/(count-1) && level<1){
27      self.voiceImageV.image = [UIImage imageNamed:@"voice2.jpg"];
28    }else if(level == 1){
29      self.voiceImageV.image = [UIImage imageNamed:@"voice3.jpg"];
30    }
31  }
32  @end

在例2-6中,第11~12行代码为滑块控件添加监听器方法,并设置数值变化的监听方法是valueChange;第15~31行代码则是方法valueChange的具体实现,该方法通过划分UISlider控件,更换不同的表示音量的图片,从而实现了对音量的控制。

4. 在模拟器上运行程序

单击Xcode工具的运行按钮,在模拟器上运行程序。程序运行成功以后,拖动滑块,发现“音量”可以根据滑块的拖动来改变大小。使用滑块控制音量的部分运行结果如图2-42所示。

图像说明文字

图2-42 使用滑块实现音量调节

2.7 分段控件(UISegmentControl)

2.7.1 分段控件概述

目前,很多手机App程序都会在界面上设计一栏按钮,这些按钮可以通过切换,在屏幕上展现不同的内容,例如,网易新闻页面频道栏中的头条、娱乐、图片等,在iOS中,这种可以在不同类别信息间进行切换的控件,称为分段控件,接下来,通过一张图片来展示分段控件的应用场景,如图2-43所示。

未命名:Users:gaomeiyun:Desktop:分段控件.png

图2-43 公交换乘的应用

分段控件使用UISegmentControl表示,它继承自UIControl,是一个可活动的控件。同其他控件一样,分段控件也可以通过拖曳的方式创建。将对象库中的Segment Control控件拖曳到Main.storyboard编辑界面中并选中,在Xcode右侧会出现UISegmentControl的属性检查器面板,如图2-44所示。

image306

图2-44 UISegmentControl的属性检查器面板

从图2-44中可以看出,UISegmentControl控件属性检查器面板中的属性比较少,其中,Segments属性的值是一个整数,它用于控制分段控件被分为几段;Segment属性则是一个列表框,它所包含的列表项随着Segments属性设置的值而改变,例如,Segments的属性设为4,那么Segment的列表框将包含4个列表项,并且Segment 0 代表第1个分段,Segment 1代表第2个分段,依次类推。

2.7.2 实战演练——使用分段控件控制“花朵”

分段控件在实际开发中应用是非常广泛的,为了帮助大家更好地掌握分段控件,接下来,我们使用分段控件开发一个控制花朵颜色的案例,该案例中共有3个分段,单击每个分段就会出现不同颜色的花朵,具体步骤如下。

1.创建工程,设计界面

(1)新建一个Single View Application应用,命名07_UISegmentControl,然后在Main.storyboard界面中添加一个UILabel控件、一个UIImageView控件和一个UISegmentControl控件,其中,UILabel控件用于提示用户选择花朵颜色,UIImageView控件用于显示花朵,UISegmentControl控件用于控制花朵的显示。

(2)将提前准备好的图片放到Supporting Files文件中,将UISegmentControl的Segments属性设置为3,Segment属性分别设置为对应的花朵图片,设计好的界面如图2-45所示。

图片 543

图2-45 使用分段控件控件花朵的界面

2.创建控件对象的关联

单击Xcode 6.1界面右上角的图片 75图标,进入控件与代码的关联界面,为UIImageView控件添加表示图片对象的属性,命名为img;同理,为UISegmentControl控件添加单击按钮的方法,命名为selectchange,添加完成后的界面如图2-46所示。

图片 137

图2-46 为控件对象创建关联

3. 通过代码实现用户登录的功能

完成控件对象的关联后,就可以通过代码实现花朵的切换了。进入ViewController.m文件,在selectchange方法中,根据分段控件的Segment属性判断单击的是哪个分段,从而控制不同颜色花朵的显示。使用分段控件控制花朵的代码如例2-7所示。

【例2-7】ViewController.m

1  #import "ViewController.h"
2  @interface ViewController ()
3  - (IBAction)selectchange:(id)sender;// 声明用于切换图片的分段控件
4  @property (weak, nonatomic) IBOutlet UIImageView *img;//声明一个图片控件
5  @end
6  @implementation ViewController
7  - (void)viewDidLoad {
8    [super viewDidLoad];
9  }
10  - (IBAction)selectchange:(id)sender {
11    // 创建要切换的图片对象
12    UIImage *img1=[UIImage imageNamed:@"flower_01.jpg"];
13    UIImage *img2=[UIImage imageNamed:@"flower_02.jpg"];
14    UIImage *img3=[UIImage imageNamed:@"flower_03.jpg"];
15    switch ([sender selectedSegmentIndex]) {
16      case 0:
17        self.img.image=img1;
18        break;
19      case 1:
20        self.img.image=img2;
21        break;
22      case 2:
23        self.img.image=img3;
24        break;
25      default:
26        break;
27    }
28  }
29  @end

在例2-7中,第12~14行代码创建了3个UIImage对象;第15~28行代码通过判断分段控件选中的位置,为UIImageView对象设置图片。

4. 在模拟器上运行程序

单击Xcode工具的运行按钮,在模拟器上运行程序。程序运行成功后,单击分段控件中的每个分段,发现分段控件可以按照期望控制不同颜色的花朵了。效果如图2-47所示。

图像说明文字

图2-47 使用分段控件控制花朵的运行结果

2.8 数据选择控件

2.8.1 日期选择控件(UIDatePicker)

UIDatePicker是一个可以用来选择日期和时间的控件,它继承自UIControl,是一个可以与用户交互的控件。例如,计时器应用中就用到了UIDatePicker控件,如图2-48所示。

未命名:Users:gaomeiyun:Desktop:计时器.png

图2-48 计时器应用

UIDatePicker控件同样可以通过拖曳的方式创建,从对象库中找到Date Picker控件,并将其拖曳到Main.storyboard编辑界面中,这时,在Xcode右侧看到UIDatePicker属性检查器面板中的相关属性,如图2-49所示。

未命名:Users:gaomeiyun:Desktop:时间选择器属性.png

图2-49 UIDatePicker的属性检查器面板

图2-49所示的是UIDatePicker所支持的一些属性,其中,Mode和Date属性都支持多种选项,下面针对这两种属性进行详细讲解。

1. Mode

Mode属性用于设置UIDatePicker的模式,它包含4种选项,单击Mode属性的下拉列表,如图2-50所示。

未命名:Users:gaomeiyun:Desktop:datepicker的属性.png

图2-50 mode属性的4种选项

从图2-50中可以看出,UIDatePicker控件有4种模式可以选择,这4种模式的相关讲解具体如下:

  • Time:该UIDatePicker控件只显示时间,不显示日期。
  • Date:该UIDatePicker控件只显示日期,不显示时间。
  • Date and Time:该UIDatePicker控件同时选择日期和时间。
  • Count Down Timer:该UIDatePicker控件仅显示倒计时器。

2. Date

Date属性用于设置日期选择器的当前时间,它包含两个选项,单击Date属性的下拉列表,如图2-51所示。

未命名:Users:gaomeiyun:Desktop:Date属性.png

图2-51 Date属性的选项

从图2-51中可以看出,Date属性支持两种选项,这两种选项所表示的含义具体如下。

  • Current Date:表示系统当前的时间。
  • Custom:表示自定义的时间,该时间用户可以任意指定。

针对日期选择控件在属性检查器面板中所支持的属性,UIDatePicker类提供了对应的属性,接下来,通过一张表来描述UIDatePicker类提供的常见属性,见如表2-12。

表2-12 UIDatePicker提供的常见属性

属性声明

功能描述

@property (nonatomic) UIDatePickerMode datePickerMode;

设置UIDatePicker的模式

@property (nonatomic, retain) NSLocale*locale;

设置UIDatePicker为国际化时间

@property (nonatomic, retain) NSDate *date;

设置UIDatePicker的当前时间

@property (nonatomic) NSTimeInterval countDownDuration;

当UIDatePicker模式为Count Down Timer时,设置剩余时间

表2-12中列举了UIDatePicker类的常见属性,其中,countDownDuration属性是专门针对CountDown Timer模式的,它用于获取倒计时的剩余时间。

2.8.2 实战演练——倒计时

在UIDatePicker的属性检查器面板中,如果将Mode属性设置为Count Down Timer,就可以将UIDatePicker控件当作倒计时器使用。接下来,通过一个案例来演示如何使用UIDatePicker控件实现倒计时的功能,具体步骤如下。

1.界面设计

(1)新建一个Single View Application应用,命名08_UIDatePicker,然后在Main.storyboard界面中添加一个UIDatePicker控件、一个UIButton控件,其中,UIDatePicker控件用于显示时间,UIButton控件用于开始计时。为了界面美观,我们在界面中添加几个UIImageView控件,作为倒计时的图标。

(2)将提前准备好的图片放到Supporting Files文件中,将UIDatePicker控件的Mode属性设置为Count Down Timer,Date属性设置Custom,设计好的界面如图2-52所示。

图片 145

图2-52 倒计时界面

2.创建控件对象的关联

单击Xcode 6.1界面右上角的图片 86图标,进入控件与代码的关联界面,为UIDatePicker控件创建表示日期控件的属性,命名为datepicker,为UIButton控件添加单击事件,命名为click。另外,由于单击按钮后,相当于启动了定时器更新UIDatePicker控件,这时,需要禁用UIButton控件和UIDatePicker控件,并更改按钮前面的图片,因此,需要为UIButton、UIDatePicker和UIImageView分别添加一个属性。添加完成后的界面如图2-53所示。

图片 147

图2-53 创建控件对象的关联

3. 通过代码实现用户登录的功能

完成控件对象的关联后,就可以通过代码实现倒计时的功能了,进入ViewController.m文件,在click方法中,首先获取倒计时的剩余时间,然后启动定时器定时更新UIDatePicker的时间。ViewController.m文件的代码如例2-8所示。

【例2-8】ViewController.m

1  #import "ViewController.h"
2  @interface ViewController ()
3  - (IBAction)click:(id)sender;
4  @property (weak, nonatomic) IBOutlet UIButton *btn_start;
5  @property (weak, nonatomic) IBOutlet UIImageView *img;
6  @property (weak, nonatomic) IBOutlet UIDatePicker *datepicker;
7  @end
8  @implementation ViewController
9  NSTimer *timer;
10  NSTimeInterval lefttime;
11  - (void)viewDidLoad {
12    [super viewDidLoad];
13  }
14  - (IBAction)click:(id)sender {
15    // 获取倒计时器的剩余时间
16    lefttime=self.datepicker.countDownDuration;
17    // 禁用UIDatePicker和UIButton控件
18    self.datepicker.enabled=NO;
19    [sender setEnabled:NO];
20    // 替换图片
21     UIImage *image=[UIImage imageNamed:@"img_03"];
22     self.img.image=image;
23    // 初始化一个字符串,用于提示用户开始倒计时
24    NSString *message=[NSString stringWithFormat:@"您还剩下【%f】秒", lefttime];
25    // 创建一个警告框,提示开始倒计时
26    UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"开始倒计时" 
27    message:message delegate:nil cancelButtonTitle:@"确定" 
28    otherButtonTitles:nil, nil];
29    // 显示UIAlertView控件
30    [alert show];
31    // 启用计时器,控制每隔60秒执行一次tickDown方法
32    timer=[NSTimer scheduledTimerWithTimeInterval:60 target:self 
33        selector:@selector(tickDown)userInfo:nil repeats:YES];
34  }
35  -(void) tickDown{
36    lefttime-=60;
37    self.datepicker.countDownDuration=lefttime;
38    if (lefttime<=0) {
39      // 取消定时器
40      [timer invalidate];
41      // 启用UIDatePicker和UIButton控件,
42      self.datepicker.enabled=YES;
43      self.btn_start.enabled=YES;
44      // 替换图片
45      UIImage *image=[UIImage imageNamed:@"img_02"];
46      self.img.image=image;
47    }
48  }
49  @end

在例2-8中,click方法是倒计时功能的具体实现,在该方法中,第32~34行代码启动了一个定时器,用于控制每隔60秒执行一次tickDown方法,而tickDown方法每执行一次,程序就会将剩余时间减少60秒,直到剩余时间小于等于0为止。

4. 在模拟器上运行程序

单击Xcode工具的运行按钮,在模拟器上运行程序。程序运行成功后,单击开始计时的按钮,会弹出一个提示框,提示剩余时间,单击确定按钮后,就可以看到该倒计时器每隔60秒跳动一次,剩余时间减少1分钟。以开始时间为1小时4分钟为例,倒计时的效果如图2-54所示。

图像说明文字

图2-54 倒计时效果

2.8.3 选择控件(UIPickerView)

除了日期选择控件外,还有一种选择控件是UIPickerView,它直接继承于UIView,是一个既能生成单列选择器,也能生成多列选择器,又能自定义外观的静态控件。为了让大家更好地认识什么是选择控件,接下来通过一张图片展示UIPickerView的使用场景,如图2-55所示。

image335

图2-55 UIPickerView的使用场景

图2-55所示的是一个水果机应用的界面,该应用界面中的水果选择控件是使用UIPickerView实现的。

同样,将Picker View从对象库中拖曳到Main.storyboard编辑界面并选中, Xcode右侧出现了UIPickerView的属性检查器面板,该面板用于设置UIPickerView的相关属性,如图2-56所示。

图片 6

图2-56 UIPickerView的属性检查器面板

图2-56所示了UIPickerView的Behavior属性,该属性用于显示选中行的标记,一般以高亮背景作为选中标记。同时,UIPickerView类也提供了相应的属性,接下来通过一张表来列举UIPickerView的常见属性,见表2-13。

表2-13 UIPickerView的常见属性

方法声明

功能描述

@property(nonatomic,assign) id<UIPickerViewDataSource> dataSource;

设置数据源

@property(nonatomic,assign) id <UIPickerViewDelegate> delegate;

设置代理

@property(nonatomic) BOOL showsSelectionIndicator;

设置是否显示UIPickerView的选中标记

@property(nonatomic,readonly) NSInteger numberOfComponents;

获取UIPickerView指定列中包含的列表项的数量,该属性权限为只读

表2-13列举了UIPickerView的一些常见属性,其中dataSource和delegate这两个属性非常重要,接下来,针对它们进行详细讲解。

1. dataSource

dataSource代表数据源,该属性用于指定UIPickerView的数据源,它知道该控件应该展示的列数和行数,但是前提要遵守UIPickerViewDataSource协议,该协议的定义方式如下所示。

 @protocol UIPickerViewDataSource<NSObject>// 数据源协议
 @required
 // 返回选择器总共有多少列
 - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;
 // 返回选择器每列总共有多少行
 - (NSInteger)pickerView:(UIPickerView *)pickerView 
 numberOfRowsInComponent:(NSInteger)component;
 @end

从上述可以看出,UIPickerViewDataSource协议定义了两个方法,这些方法是使用@required关键字修饰的必须要实现的方法,通过委托代理的方式限制数据信息展示的样式,如行数和列数,因此我们又称之为数据源协议。

2. delegate

delegate表示代理,该属性用于设定UIPickerView的代理,实现代理对UIPickerView的监听,但是前提要遵守UIPickerViewDelegate协议,该协议的定义方式如下所示。

 @protocol UIPickerViewDelegate<NSObject>// 代理协议
 @optional
 // 返回第component列每一行的宽度
 - (CGFloat)pickerView:(UIPickerView *)pickerView 
 widthForComponent:(NSInteger)component;
 // 返回第component列每一行的高度
 - (CGFloat)pickerView:(UIPickerView *)pickerView 
 rowHeightForComponent:(NSInteger)component;
 // 设置选择器每行显示的文本内容
 - (NSString *)pickerView:(UIPickerView *)pickerView 
 titleForRow:(NSInteger)row forComponent:(NSInteger)component;
 // 设置选择器每行显示的视图内容
 - (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row 
 forComponent:(NSInteger)component reusingView:(UIView *)view;
 //单击选择器某列某行时,就会调用这个方法
 - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row 
 inComponent:(NSInteger)component;
 @end

从上述代码可以看出,UIPickerViewDelegate协议定义了一些方法,这些方法都可以展示选择器每行每列的信息,且方法是可选择实现的。例如,pickerView:titleForRow:forComponent方法根据相应的数据,展示选择器每行对应的文本内容。

除了协议方法之外,UIPickerView类也定义了一些常见的方法,接下来通过一张表列举UIPickerView的常见方法,见表2-14。

表2-14 UIPickerView的常见方法

方法声明

功能描述

-(NSInteger)numberOfRowsInComponent:(NSInteger)component;

返回第component列有多少行

- (CGSize)rowSizeForComponent:(NSInteger)component;

返回第component列中一行的尺寸

- (UIView *)viewForRow:(NSInteger)row forComponent:(NSInteger)component;

设置选择器某列某行的视图内容

- (void)reloadAllComponents;

刷新所有列的数据

- (void)reloadComponent:(NSInteger)component;

刷新某一列的数据

- (void)selectRow:(NSInteger)row inComponent:(NSInteger)component animated:(BOOL)animated;

设置是否动画选中某列某行

- (NSInteger)selectedRowInComponent:(NSInteger)component;

返回选中的是第component列的第几行

表2-14列举了UIPickerView类一些常见的方法,这些方法配合使用,可以协调展示不同样式的选择器。

2.8.4 实战演练——点菜系统

随着社会的发展,人们对生活质量的要求不断提高,也越来越注重于饮食。去酒店吃饭成了人们生活中的一部分。为了提高酒店的服务质量,开发一套完善的酒店点菜系统是必要的。接下来,带领大家使用UIPickerView开发一个“点餐系统”,具体步骤如下。

1.创建工程,设计界面

(1)新建一个Single View Application应用,名称为09_UIPickerView,然后在Main.storyboard界面中添加1个UIPickerView、1个UIView、3个UIButton和9个UILabel,其中UIPickerView用于滚动选中菜系内容,UILabel用于显示选择器选中的菜系,UIButton用于随机选中菜系。

(2)设置UIView的背景颜色,并将用于保存菜系数据的foods.plist文件放到Supporting Files文件中,设计好的界面如图2-57所示。

图片 544

图2-57 点菜系统界面

2.创建控件对象的关联

(1)单击Main.storyboard左下角的图片 153图标,打开文档大纲区,选中UIPickerView右击,弹出一个黑框列表,从该列表dataSource选项后的空圆圈拖线到文档大纲区中的控制器文件,设置UIPickerView的dataSource为控制器,如图2-58所示。

图片 154

图2-58 设置UIPickerView的dataSource为控制器

(2)同样的方式,设置UIPickerView的delegate为控制器,如图2-59所示。

图片 155

图2-59 设置UIPickerView的delegate为控制器

(3)使用控件和代码关联的方式,为UIButton添加单击事件,添加UILabel和UIPickerView属性,添加完成后的界面如图2-60所示。

图片 156

图2-60 完成控件对象关联的界面

3. 通过代码实现点菜的功能

完成控件对象的关联后,就可以通过代码实现点菜的功能了。进入ViewController.m文件,遵守数据源和代理协议,将数据信息展示到UIPickerView控件中,并将选中的行内容显示到对应UILabel上,代码如例2-9所示。

【例2-9】ViewController.m

1  #import "ViewController.h"
2  // 遵守数据源和代理协议
3  @interface ViewController ()<UIPickerViewDataSource, UIPickerViewDelegate>
4  @property (nonatomic, strong)NSArray *foods; // 保存plist文件中所有的food
5  @property (weak, nonatomic) IBOutlet UILabel *fruitLabel;
6  @property (weak, nonatomic) IBOutlet UILabel *mainLabel; 
7  @property (weak, nonatomic) IBOutlet UILabel *drinkLabel; 
8  @property (weak, nonatomic) IBOutlet UIPickerView *pickerView;
9  - (IBAction)random; // 生成随机套餐方法
10  - (IBAction)certain; // 确定方法
11  - (IBAction)cancel; // 取消方法
12  @end
13  @implementation ViewController
14  // 懒加载数组
15  - (NSArray *)foods
16  {
17    if (_foods == nil) {
18      _foods = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] 
19  pathForResource:@"foods" ofType:@"plist"]];
20    }
21    return _foods;
22  }
23  - (void)viewDidLoad {
24    [super viewDidLoad];
25    for (int i = 0; i < 3; i++) {  // 选中每一列的第一行
26      [self pickerView:nil didSelectRow:0 inComponent:i];
27    }
28  }
29  #pragma mark - UIPickerViewDataSource
30  // 总共有多少列
31  - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
32  {
33    return self.foods.count;
34  }
35  // 每列总共有多少行
36  - (NSInteger)pickerView:(UIPickerView *)pickerView 
37  numberOfRowsInComponent:(NSInteger)component
38  {
39    NSArray *subFood = self.foods[component];
40    return subFood.count;
41  }
42  #pragma mark - UIPickerViewDelegate
43  // 第component列的第row行显示文字内容
44  - (NSString *)pickerView:(UIPickerView *)pickerView 
45  titleForRow:(NSInteger)row forComponent:(NSInteger)component
46  {
47    return self.foods[component][row];
48  }
49  // 选中了第component列的第row行
50  - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row 
51  inComponent:(NSInteger)component
52  {
53    // 将选中行的文本显示到对应的Label
54    if (component == 0) {    // 水果Label
55      self.fruitLabel.text = self.foods[component][row];
56    }else if (component == 1){ // 主菜Label
57      self.mainLabel.text = self.foods[component][row];
58    }else if(component == 2){  // 饮料Label
59      self.drinkLabel.text = self.foods[component][row];
60    }
61  }
62  // 设置行高
63  - (CGFloat)pickerView:(UIPickerView *)pickerView 
64  rowHeightForComponent:(NSInteger)component
65  {
66    return 35;
67  }
68  // 随机选中一份套餐
69  - (IBAction)random {
70    for (int component = 0; component < self.foods.count; component++) {
71      // 1.第component列数组的总长度
72      int count = [self.foods[component] count];
73      // 2.旧的行号
74       int oldRow = [self.pickerView selectedRowInComponent:component];
75      // 3.第几行(默认新的行号跟旧的行号一样)
76      int row = oldRow;
77      // 4.保证行数跟上一次不一样
78      while (row == oldRow) {
79        row = arc4random()%count;
80      }
81      // 5.让pickerView主动选中第compoent列的第row行
82      [self.pickerView selectRow:row inComponent:component animated:YES];
83      // 6.设置label的文字
84      [self pickerView:nil didSelectRow:row inComponent:component];
85    }
86  }
87  // 单击确定
88  - (IBAction)certain {
89    // 提示用户点餐成功
90    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"点餐成功" 
91  message:@"请稍后。。" delegate:nil cancelButtonTitle:@"好的" 
92  otherButtonTitles:nil, nil];
93    [alert show];
94  }
95  // 单击取消
96  - (IBAction)cancel {
97    // 直接回到初始化时候
98    for (int i = 0; i < 3; i++) {
99       [self pickerView:nil didSelectRow:0 inComponent:i];
100       [self.pickerView selectRow:0 inComponent:i animated:YES];
101    }
102  }
103 @end

在例2-9中,第3行代码遵守了数据源和代理协议;第4行代码定义了一个数组,用于保存plist文件中所有的foods数据;第14~22行代码使用懒加载的方法初始化数组;第29~67行代码分别为数据源和代理协议中定义的一些方法,用于展示数组中的数据;第69~102行代码分别为单击随机、确定和取消按钮后执行的行为。

4. 在模拟器上运行程序

单击Xcode工具的运行按钮,在模拟器上运行程序。程序运行成功后,UIPickerView选中的数据成功展示到Label中,单击随机、确定和取消按钮,也都一一对应完成了相应功能。程序运行结果的部分结果如图2-61所示。

图像说明文字

图2-61 程序运行部分场景图

图像说明文字 多学一招:懒加载

我们知道iOS设备的内存有限。如果程序在启动后就一次性加载应用程序将来会用到的所有资源(如大量数据、图片、音频等),那么就有可能会耗尽iOS设备的内存,就会造成应用程序运行缓慢,或者出现卡顿,甚至于应用程序会发生崩溃。同很多语言一样,iOS中用“懒加载”的方式来加载这些资源,对这些资源进行合理化管理。

懒加载又称之为“延迟加载”,说通俗一点,就是在开发中,程序启动的时候不立刻使用的资源先不加载,当程序运行中需要使用资源的时候再去加载它。懒加载用于get方法,主要有以下好处。

  • 效率低,占用内存小。
  • 不必将创建对象的代码全部写在viewDidLoad方法中,代码的可读性更强。
  • 每个控件的get方法中负责自身的实例化,代码彼此之间的独立性强,耦合度低。

2.9 屏幕滚动控件(UIScrollView)

2.9.1 屏幕滚动控件概述

移动设备的屏幕大小是极其有限的,因此直接展示在用户眼前的内容也是有限的。当屏幕展示的内容较多、超出一个屏幕时,用户可以通过滚动的方式来查看屏幕外的内容。在iOS中,UIScrollView是一个支持滚动的控件,它直接继承自UIView,可以用来展示大量的内容,并且可以通过滚动的方式查看所有的内容。为了让大家更好地理解,接下来通过一张图片来展示UIScrollView的使用场景,如图2-62所示。

image355

图2-62 UIScrollView的使用场景

图2-62所示是一个新闻页面,该页面有很多内容需要展示,因此,该页面中包含了一个UIScrollView控件,用户可以通过滚动的方式来在有限的屏幕中查看更多内容。

UIScrollView控件同其他控件一样,都包含很多属性,同样,从对象库中找到Scroll View,将其拖曳到Main.storyboard编辑界面中,在Xcode右侧会出现UIScrollView的属性检测器面板,该面板可以设置UIScrollView的相关属性,如图2-63所示。

image357

图2-63 UIScrollView的属性检测器面板

针对UIScrollView属性检查器面板设置的属性,UIScrollView类也定义了与之对应的属性,接下来通过一张表来列举UIScrollView的常见属性,见表2-15。

表2-15 UIScrollView的常见属性

属性声明

功能描述

@property(nonatomic) CGPoint contentOffset;

设置滚动视图的滚动偏移量

@property(nonatomic)CGSize contentSize;

设置滚动视图的滚动范围

@property(nonatomic)UIEdgeInsets contentInset;

设置滚动视图的额外滚动区域

@property(nonatomic,assign) id<UIScrollViewDelegate>delegate;

设置代理

@property(nonatomic,getter=isScrollEnabled) BOOL scrollEnabled;

设置滚动视图是否允许滚动

@property(nonatomic,getter=isPagingEnabled) BOOL pagingEnabled;

设置滚动视图是否开启分页

@property(nonatomic) BOOL showsHorizontalScrollIndicator;

设置滚动视图是否显示水平滚动条

@property(nonatomic)BOOL showsVerticalScrollIndicator;

设置滚动视图是否显示垂直滚动条

@property(nonatomic) CGFloat minimumZoomScale;

设置滚动视图的最小缩放比例

@property(nonatomic) CGFloat maximumZoomScale;

设置滚动视图的最大缩放比例

@property(nonatomic) BOOL scrollsToTop;

设置滚动视图是否滚动到顶部

表2-15列举了UIScrollView的常见属性,其中contentOffset、contentSize、contentInset是UIScrollView支持的3个控件显示区域属性, delegate为代理属性,这些属性都比较重要,接下来针对这几个属性进行详细介绍。

1. contentSize

该属性是一个CGSize类型的值,CGSize是一个结构体类型,它包含width、height两个成员变量,代表着该UIScrollView所需要显示内容的完整高度和完整宽度。例如,内容视图为灰色部分,它的大小为320×544,而ScrollView视图的大小只有320×460,由于内容视图超出了ScrollView可显示的大小,因此,需要滚动屏幕来查看内容,如图2-64所示。

图像说明文字

图2-64 contentSize属性

2.contentInset

该属性是一个UIEdgeInsets类型的值,UIEdgeInsets也是一个结构体类型,它包含top、left、bottom、right 4个成员变量,分别代表着该UIScrollView所需要显示内容在上、左、下、右的留白。例如,内容视图为灰色部分,它的大小为320×480,而ScrollView的大小只有320×460,由于内容视图超出了ScrollView可显示的大小,并且上方要留一部分空白显示其他控件,因此,需要滚动屏幕来查看内容,如图2-65所示。

图像说明文字

图2-65 contentInset属性

3.contentOffset

该属性是一个CGPoint类型的值,CGPoint也是一个结构体类型,它包含x 、y两个成员变量,代表内容视图的坐标原点与该UIScrollView坐标原点的偏移量,如图2-66所示。

图像说明文字

图2-66 contentOffset属性

4.delegate

该属性是一个id类型的值,它可以指定代理对象。在ScrollView中定义了一个UIScrollViewDelegate协议,该协议定义了许多可以监听UIScrollView滚动过程的方法,例如,要想监听ScrollView的缩放和拖曳,可以通过遵守UIScrollViewDelegate协议,指定ScrollView的代理对象来实现。UIScrollViewDelegate协议的定义方式如下所示。

 @protocol UIScrollViewDelegate<NSObject>
 @optional
 // 滚动UIScrollView时就会调用该方法
 - (void)scrollViewDidScroll:(UIScrollView *)scrollView;
 // 缩放UIScrollView时就会调用该方法
 - (void)scrollViewDidZoom:(UIScrollView *)scrollView; 
 // 即将拖曳UIScrollView时就会调用该方法
 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
 // 即将停止拖曳UIScrollView时就会调用该方法
 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView 
 withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)
 targetContentOffset;
 // 停止拖曳UIScrollView时就会调用该方法
 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView 
 willDecelerate:(BOOL)decelerate;
 // UIScrollView即将减速时就会调用该方法
 - (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView;
 // UIScrollView减速完成时就会调用该方法
 - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
 // 返回缩放的视图,这个视图必须是UIScrollView的子视图
 - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView; 
 // UIScrollView即将缩放时就会调用该方法
 - (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView 
 withView:(UIView *)view; 
 // UIScrollView完成缩放时就会调用该方法
 - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:
 (UIView *)view atScale:(CGFloat)scale; 
 @end

从上述代码中可以看出,UIScrollViewDelegate协议中定义了许多供代理监听的方法,这些方法会在滚动视图的不同状态下被调用。例如,scrollViewDidScroll方法是改变滚动视图偏移量时调用的方法,该方法会在视图滚动后执行。

2.9.2 实战演练——喜马拉雅

UIScrollView在iOS开发中经常使用,它主要用于在有限的屏幕上展示更多的内容。为了大家更好地掌握UIScrollView的使用,接下来带领大家搭建一个喜马拉雅的应用界面,具体步骤如下。

1.界面设计

(1)新建一个Single View Application应用,名称为10_UIScrollView,然后在Main.storyboard界面中添加1个UIScrollView、2个UIView、1个UILabel和12个UIButton,其中UIButton只作为显示,不支持单击事件,UIScrollView用于滚动它内部包含的内容视图。

(2)将提前准备好的图片放到Images.xcassets文件中,并为UIButton设置普通和高亮状态下的背景图片,设计好的界面如图2-67所示。

在图2-67中,UIScrollView上添加了7个UIButton,它们分别设置了普通状态下的背景图片,由于屏幕尺寸的限制,无法展示UIScrollView最底部的一个UIButton。需要注意的是,只有添加到UIScrollView内部的控件才能实现滚动,如同绑定的关系。

图片 545

图2-67 搭建好的喜马拉雅界面

2.创建控件对象的关联

单击Xcode 6.1界面右上角的图片 165图标,进入控件与代码的关联界面,使用控件和代码关联的方式,为UIScrollView和其内部最底部的UIButton添加两个属性,分别命名为scrollView和lastView,添加完成后的界面如图2-68所示。

图片 1669

图2-68 创建视图对象的关联

从图2-68中可以看出,完成控件对象的关联后,成功添加了两个属性。

3. 通过代码实现滚动的功能

完成控件对象的关联后,就可以通过代码实现滚动的功能了。进入ViewController.m文件,在viewDidLoad方法中实现滚动的功能,代码如例2-10所示。

【例2-10】ViewController.m

1  #import "ViewController.h"
2  @interface ViewController ()
3  // 定义了两个属性scrollView和lastView,分别表示滚动视图和其内部最底部的视图
4  @property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
5  @property (weak, nonatomic) IBOutlet UIButton *lastView;
6  @end
7  @implementation ViewController
8  - (void)viewDidLoad {
9    [super viewDidLoad];
10    // 1.获取lastView的最大Y值
11    CGFloat lastViewH = CGRectGetMaxY(self.lastView.frame) + 10;
12    // 2.设置scrollView的滚动范围
13    self.scrollView.contentSize = CGSizeMake(0, lastViewH);
14    // 3.设置scrollView的偏移量
15    self.scrollView.contentOffset = CGPointMake(0, -54);
16    // 4.设置scrollView的间距
17    self.scrollView.contentInset = UIEdgeInsetsMake(54, 0, 44, 0);
18  }
19  @end

在例2-10中,第8~18行代码是viewDidLoad方法,该方法中首先根据最底部视图的Y值确定scrollView的滚动范围,然后设置scrollView的偏移量和间距,协调滚动视图跟其他视图的位置,使界面更加美观。

4. 在模拟器上运行程序

单击Xcode工具的运行按钮,在模拟器上运行程序。程序运行成功后,发现视图可以滚动了,并且最底部的视图也能显现出来,滚动界面的部分场景图片如图2-69所示。

图像说明文字

图2-69 滚动界面

2.10 页控件(UIPageControl)

2.10.1 页控件概述

顾名思义,页控件是一个可以实现翻页效果的控件,它是一个比较简单的控件,由N个小圆点组成,每个小圆点代表一个页面,并且当前页面使用高亮的圆点显示。在iOS中,页控件使用UIPageControl类来表示,它直接继承于UIControl:UIView,是一个可以与用户交互的活动控件。接下来通过一张图片来展示UIPageControl的使用场景,如图2-70所示。

image376

图2-70 UIPageControl的使用场景

图2-70所示了5个小圆点,并且第2个小圆点是高亮状态,说明页控件包含5个页面,并且当前页面是第2个页面。

页控件Page Control同样可以从对象库中找到。将Page Control控件从对象库中拖曳到Main.storyboard编辑界面中,在Xcode右侧查看UIPageControl的属性检测器面板,如图2-71所示。

image378

图2-71 UIPageControl的属性检测器面板

图2-71显示的是UIPageControl所支持的一些属性,通过对这些属性的设置,可以使页控件发生相应的变化。

针对UIPageControl属性检查器面板设置的属性,UIPageControl类也定义了与之对应的属性,接下来通过一张表来列举UIPageControl的常见属性,如表2-16所示。

表2-16 UIPageControl的常见属性

属性声明

功能描述

@property(nonatomic) NSInteger numberOfPages;

设置总共有多少页

@property(nonatomic) NSInteger currentPage;

设置当前是第几页

@property(nonatomic,retain) UIColor *pageIndicatorTintColor;

设置页码指示器的颜色

@property(nonatomic,retain) UIColor *currentPageIndicatorTintColor;

设置当前页码指示器的颜色

表2-16列举了UIPageControl所支持的一些属性,它们均可以设置页控件的外观。

2.10.2 实战演练——自动轮播器

实际项目中,经常会把UIScrollView和UIPageControl结合使用,接下来,带领大家使用这两个控件完成一个自动轮播器,具体步骤如下。

1.创建工程,设计界面

(1)新建一个Single View Application应用,名称为10_UIScrollView和UIPageControl,然后在Main.storyboard界面中添加一个UIScrollView、一个UIPageControl、一个UIView和一个UILabel,其中,UIScrollView用于显示轮播图片,UIPageControl用于显示页码。

(2)将提前准备好的图片放到Images.xcassets文件中,并为UIPageControl的圆点和高亮圆点分别设置白色和蓝色,设计好的界面如图2-72所示。

图片 507

图2-72 搭建好的界面

2.创建控件对象的关联

(1)单击Main.storyboard左下角的图片 172图标,打开文档大纲区,选中UIScrollView右击,弹出一个黑框列表,从该列表delegate选项后的空圆圈拖线到文档大纲区中的控制器文件,设置UIScrollView的delegate为控制器,如图2-73所示。

图片 173

图2-73 设置UIScrollView的delegate为控制器

(2)单击Xcode 6.1界面右上角的图片 174图标,进入控件与代码的关联界面,使用控件和代码关联的方式,为UIScrollView和UIPageControl添加两个属性,分别命名为scrollView和pageControl,用于表示轮播器和页码指示器,添加完成后的界面如图2-74所示。

图片 175

图2-74 创建UIScrollView和UIPageControl控件对象的关联

3. 通过代码实现自动轮播的功能

完成控件对象的关联后,就可以通过代码加载图片,并实现自动轮播的功能了。进入ViewController.m文件,在viewDidLoad方法中完成相对的功能,代码如例2-11所示。

【例2-11】ViewController.m

1  #import "ViewController.h"
2  @interface ViewController ()<UIScrollViewDelegate>
3  // 定义两个属性scrollView和pageControl,分别表示轮播器和页码
4  @property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
5  @property (weak, nonatomic) IBOutlet UIPageControl *pageControl;
6  @property (nonatomic, strong) NSTimer *timer; // 定时器
7  @end
8  @implementation ViewController
9  - (void)viewDidLoad {
10    [super viewDidLoad];
11    // 1.图片的总数
12    int count = 6;
13    // 2.imageView的尺寸和Y值
14    CGFloat imageY = 0;
15    CGFloat imageW = self.scrollView.frame.size.width;
16    CGFloat imageH = self.scrollView.frame.size.height;
17    // 3.循环添加5张图片到scrollView上
18    for (int i = 0; i<count; i++) {
19      UIImageView *imageView = [[UIImageView alloc] init];
20      CGFloat imageX = i * imageW;
21      imageView.frame = CGRectMake(imageX, imageY, imageW, imageH);
22      // 拼接图片的名称
23      NSString *imageName = [NSString 
24                   stringWithFormat:@"img_0%d",i+1];
25      imageView.image = [UIImage imageNamed:imageName];
26      [self.scrollView addSubview:imageView];
27    }
28    // 4.设置scrollView的contentSize,让视图可以滚动
29    CGFloat contentW = count * imageW;
30    self.scrollView.contentSize = CGSizeMake(contentW, 0);
31    // 5.隐藏scrollView的水平滚动条
32    self.scrollView.showsHorizontalScrollIndicator = NO;
33    // 6.设置pageControl的总页数
34    self.pageControl.numberOfPages = count;
35    // 7.设置scrollView分页
36    self.scrollView.pagingEnabled = YES;
37    // 8.开启定时器
38    [self addTimer];
39  }
40  //添加定时器方法
41  - (void)addTimer
42  {
43    self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0f 
44    target:self selector:@selector(nextImage) userInfo:nil repeats:YES];
45    [[NSRunLoop currentRunLoop] addTimer:self.timer 
46     forMode:NSRunLoopCommonModes];
47  }
48  //移除定时器方法
49  - (void)removeTimer{
50    [self.timer invalidate];
51    self.timer = nil;
52  }
53  // 定时器调用的方法
54  - (void)nextImage
55  {
56    int count = 6;// 图片的总数
57    // 增加pageControl的页码
58    int page = 0;
59    if (self.pageControl.currentPage == count - 1) {
60      page = 0;
61    } else {
62      page = self.pageControl.currentPage + 1;
63    }
64    // 计算scrollView滚动的位置
65    CGFloat offsetX = page * self.scrollView.frame.size.width;
66    CGPoint offset = CGPointMake(offsetX, 0);
67    [self.scrollView setContentOffset:offset animated:YES];
68  }
69  #pragma mark - UIScrollViewDelegate方法
70  //当scrollView正在滚动就会调用该方法
71  - (void)scrollViewDidScroll:(UIScrollView *)scrollView
72  {
73    // 根据scrollView的滚动位置决定pageControl显示第几页
74    CGFloat scrollW = scrollView.frame.size.width;
75    int page = (scrollView.contentOffset.x+scrollW*0.5)/scrollW;
76    self.pageControl.currentPage = page;
77  }
78  //开始拖曳的时候会调用该方法
79   - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
80  {
81    // 停止定时器(一旦停止,就不能再使用)
82    [self removeTimer];
83  }
84  //停止拖曳的时候会调用该方法
85  - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView 
86  willDecelerate:(BOOL)decelerate
87  {
88    [self addTimer];  // 开启定时器
89  }
90  @end

在例2-11中,第9~39行代码是viewDidLoad方法,用于设置滚动视图和页码内容;第41~52行代码为添加和移除定时器的方法;第54~68行代码为定时器每间隔2秒重复调用的方法,用于切换高亮圆点的位置;第71~89行代码均为UIScrollViewDelegate方法,分别用于设置滚动视图的分页、用户拖曳时停止定时器和停止拖曳时启动定时器。

4. 在模拟器上运行程序

单击Xcode工具的运行按钮,在模拟器上运行程序。程序运行成功后,每隔两秒钟自动切换下一张图片,一个自动播放图片的应用开发完成了,自动轮播器的部分场景如图2-75所示。

图像说明文字

图2-75 自动轮播器的部分场景

2.11 本章小结

本章首先对UI开发的始祖UIView进行了详细讲解,然后介绍了iOS开发中常用的控件,包括标签控件、图片控件、按钮控件、文本控件、开关控件、滑块控件、分段控件、数据选择控件、屏幕滚动控件和页控件,在讲解这些控件时,采用的方式都是从生活引入开发的方式,让大家带着对每个控件的基本认识去学习,并带领大家使用不同的控件开发不同的案例。

通过本章的学习,希望大家可以熟练掌握这些控件的使用,能够独立完成相关案例的开发,从而加强本章知识的学习。

【思考题】

1 . 简述什么是懒加载。

2 . 简述UIView中frame和bounds属性的区别。

扫描右方二维码,查看思考题答案!

图像说明文字

目录

推荐用户

同系列书

人邮微信
本地服务
教师服务
教师服务
读者服务
读者服务
返回顶部
返回顶部