iOS 常见控件与事件处理详解
1. UIControl 事件通知机制
UIControl 类提供了一套标准的机制来注册和接收事件。当特定事件发生时,你可以让控件通知委托类中的某个方法。
1.1 注册事件
使用
addTarget
方法来注册事件,示例代码如下:
[ myControl addTarget: myDelegate action: @selector(myActionMethod:)
forControlEvents: UIControlEventValueChanged
];
事件可以通过逻辑或(OR)组合在一起,这样你就可以在一次调用
addTarget
时指定多个事件。
1.2 支持的事件类型
| 事件类型 | 描述 |
|---|---|
| UIControlEventTouchDown | 通知所有单个触摸按下事件,当用户点击屏幕或放下额外手指时触发 |
| UIControlEventTouchDownRepeat | 当点击次数大于 1 时,通知所有多点触摸按下事件 |
| UIControlEventTouchDragInside | 当触摸在控件窗口内拖动时通知 |
| UIControlEventTouchDragOutside | 当触摸在控件窗口外拖动时通知 |
| UIControlEventTouchDragEnter | 当触摸从控件窗口外拖到窗口内时通知 |
| UIControlEventTouchDragExit | 当触摸从控件窗口内拖到窗口外时通知 |
| UIControlEventTouchUpInside | 通知所有在控件内发生的触摸抬起事件 |
| UIControlEventTouchUpOutside | 通知所有源自控件外的触摸抬起事件(前提是触摸起始于控件内) |
| UIControlEventTouchCancel | 通知所有触摸取消事件,如因手指过多或被锁定、来电中断 |
| UIControlEventValueChanged | 当控件的值发生变化时通知,用于滑块、分段控件等基于值的控件 |
| UIControlEventEditingDidBegin | 当基于文本的控件开始编辑时通知 |
| UIControlEventEditingChanged | 当基于文本的控件内文本发生变化时通知 |
| UIControlEventEditingDidEnd | 当基于文本的控件编辑结束时通知 |
| UIControlEventEditingDidEndOnExit | 当基于文本的控件通过按下返回键结束编辑时通知 |
| UIControlEventAllTouchEvents | 通知所有触摸事件 |
| UIControlEventAllEditingEvents | 通知所有基于文本的编辑事件 |
| UIControlEventAllEvents | 通知所有事件 |
除了默认事件,自定义控件类可以使用
0x0F000000
到
0x0FFFFFFF
的值范围来定义自己的事件。
1.3 移除事件动作
使用
removeTarget
方法移除一个或多个事件的动作,示例如下:
[ myControl removeTarget: myDelegate action: nil
forControlEvents: UIControlEventAllEvents
];
1.4 获取事件动作列表
-
使用
allTargets方法获取控件指定的所有动作列表:
NSSet *myActions = [ myControl allTargets ];
-
使用
actionsForTarget方法获取给定事件目标的所有动作列表:
NSArray *myActions = [ myControl actionsForTarget: UIControlEventValueChanged ];
1.5 发送事件通知
如果你正在设计自定义控件类,可以使用
sendActionsForControlEvents
方法结束对基本 UIControl 事件或自定义事件的通知,示例如下:
[ self sendActionsForControlEvents: UIControlEventValueChanged ];
2. 分段控件(Segmented Controls)
分段控件用类似于现代厨房电器(如洗碗机或微波炉)前面板的界面取代了桌面操作系统上的单选按钮。用户看到的是一个按钮栏,按下一个按钮会使其他按钮弹出。分段控件适用于为一个选项提供有限数量的相关选择。
2.1 创建控件
使用
initWithItems
方法初始化分段控件,并设置其样式,示例代码如下:
UISegmentedControl *segmentedControl = [ [ UISegmentedControl alloc ]
initWithItems: nil
];
segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
分段控件有三种不同的样式可供选择:
| 样式 | 描述 |
| — | — |
| UISegmentedControlStylePlain | 带有灰色边框的大白色按钮,适用于偏好设置单元格 |
| UISegmentedControlStyleBordered | 带有黑色边框的大白色按钮,适用于表格单元格 |
| UISegmentedControlStyleBar | 适用于导航栏的小按钮 |
如果使用
UISegmentedControlStyleBar
样式,还可以通过
tintColor
属性为整个控件设置色调:
UIColor *myTint = [ [ UIColor alloc ] initWithRed: 0.75
green: 1.0
blue: 0.75
alpha: 1.0
];
segmentedControl.tintColor = myTint;
2.2 添加和移除分段
- 添加带有标题的分段:
[ segmentedControl insertSegmentWithTitle: @"Bunnies"
atIndex: 0 animated: NO
];
[ segmentedControl insertSegmentWithTitle: @"Ponies"
atIndex: 1 animated: NO
];
- 添加带有图像的分段:
UIImage *myBunnies = [ UIImage applicationImageNamed: @"bunnies.png" ];
[ segmentedControl insertSegmentWithImage: myBunnies
atIndex: 0 animated: NO
];
- 移除单个分段:
[ segmentedControl removeSegmentAtIndex: 1 animated: YES ];
- 移除所有分段:
[ segmentedControl removeAllSegments ];
2.3 分段标题和图像操作
- 设置分段标题:
[ segmentedControl setTitle:@"Unicorms" forSegment: 0 ];
- 获取分段标题:
NSString *myTitle = [ segmentedControl titleForSegmentAtIndex: 0 ];
- 设置分段图像:
[ segmentedControl setImage: [ UIImage applicationImageNamed:@"unicorns.png" ]
forSegmentAtIndex: 0
];
- 获取分段图像:
UIImage *myImage = [ segmentedControl imageForSegmentAtIndex: 0 ];
控件本身不会对图像进行缩放,因此在设计按钮图像时需要确保其适合按钮空间。你可以使用
setWidth
方法手动设置分段的宽度:
[ segmentedControl setWidth: 64.0 forSegmentAtIndex: 0 ];
2.4 瞬时点击和默认分段设置
-
瞬时点击:默认情况下,分段控件会保留所选按钮,直到选择另一个按钮。你可以通过将
momentary属性设置为YES来改变这种行为,使按钮在按下后不久自动释放:
segmentedControl.momentary = YES;
-
设置默认分段:默认情况下,除非你指定,否则不会选择任何分段。通过设置
selectedSegmentIndex属性来设置默认分段:
segmentedControl.selectedSegmentIndex = 0;
2.5 显示和读取控件
- 显示控件:
// 添加到父视图
[ parentView addSubview: segmentedControl ];
// 添加到导航栏
self.navigationItem.titleView = segmentedControl;
-
读取控件:通过读取
selectedSegmentIndex属性来获取当前选中的分段编号:
int x = segmentedControl.selectedSegmentIndex;
为了在按钮被按下时接收通知,可以使用
addTarget
方法为
UIControlEventValueChanged
事件添加动作:
[ segmentedControl addTarget: self action:
@selector(controlPressed:)
forControlEvents: UIControlEventValueChanged
];
动作方法示例:
-(void) controlPressed: (id)sender
{
UISegmentedControl *control = (UISegmentedControl *) sender;
if (control == mySegmentedControl) {
int x = control.selectedSegmentIndex;
// 响应分段变化的额外代码
}
}
3. 开关(Switches)
开关控件取代了复选框,用于打开和关闭功能。它是最容易使用的控件之一,但仍可以在一定程度上进行自定义。
3.1 创建控件
使用
initWithFrame
方法初始化开关,框架的大小会被忽略,开关会自行确定最佳大小。示例代码如下:
UISwitch *switch = [ [ UISwitch alloc ]
initWithFrame: CGRectMake(170.0, 5.0, 0.0, 0.0)
];
3.2 替代颜色(未文档化 API)
虽然 SDK 不支持,但你可以使用未文档化的
setAlternateColors
方法将破坏性开关在激活时设置为亮橙色警告颜色,而不是标准的蓝色。不过要注意,这个 API 随时可能更改,使用未文档化 API 可能导致应用被 App Store 拒绝,因此在投入生产前要移除该功能:
[ switch setAlternateColors: YES ];
3.3 显示和读取开关
- 显示开关:
// 添加到父视图
[ parentView addSubview: switch ];
// 添加到导航栏
self.navigationItem.titleView = switch;
-
读取开关位置:通过
on属性获取开关的布尔值,以确定开关是否被激活:
BOOL switchPosition = switch.on;
-
激活开关:使用
setOn方法在代码中激活开关:
[ switch setOn: YES animated: YES ];
为了在开关被切换时接收通知,使用
addTarget
方法为
UIControlEventValueChanged
事件添加动作:
[ switch addTarget: self action: @selector(switchStatusChanged:)
forControlEvents:UIControlEventValueChanged
];
动作方法示例:
-(void) switchStatusChanged: (id)sender
{
UISwitch *control = (UISwitch *) sender;
if (control == mySwitch) {
BOOL on = control.on;
// 响应开关状态的额外代码
}
}
4. 滑块(Sliders)
滑块提供了一个可视化的范围,用户可以通过滑动条来改变值,并且可以进行配置以适应不同的数值范围。它适用于呈现具有大(但不精确)数值范围的选项,如音量设置、灵敏度控制等。
4.1 创建控件
使用
initWithFrame
方法初始化滑块,框架的高度会被忽略,可以设置为
0x0
:
UISlider *slider = [ [ UISlider alloc ] initWithFrame:
CGRectMake(0.0, 0.0, 200.0, 0.0)
];
设置滑块的值范围,使用
minimumValue
和
maximumValue
属性:
slider.minimumValue = 0.0;
slider.maximumValue = 100.0;
设置滑块的默认值:
slider.value = 50.0;
滑块可以在两端显示图像,设置方法与分段控件类似。将图像复制到 Xcode 项目的
Resources
文件夹中,示例代码如下:
[ slider setMinimumTrackImage:
[ UIImage applicationImageNamed:@"min.png" ]
forState: UIControlStateNormal
];
[ slider setMaximumTrackImage:
[ UIImage applicationImageNamed:@"max.png" ]
forState: UIControlStateNormal
];
滑块有以下几种状态可供设置不同的图像:
- UIControlStateNormal
- UIControlStateHighlighted
- UIControlStateDisabled
- UIControlStateSelected
为了调试,存在一个未文档化的 API 可以在控件内显示滑块的值。使用
setShowValue
方法:
[ slider setShowValue: YES ];
同样,要注意这个 API 随时可能更改,使用未文档化 API 可能导致应用被 App Store 拒绝,在投入生产前要移除该功能。
4.2 显示和读取滑块
- 显示滑块:
// 添加到父视图
[ parentView addSubview: slider ];
// 添加到导航栏
self.navigationItem.titleView = slider;
-
读取滑块值:通过
value属性获取滑块的浮点值:
float value = slider.value;
为了在滑块值发生变化时接收通知,使用
addTarget
方法为
UIControlEventValueChanged
事件添加动作:
[ slider addTarget: self action: @selector(sliderValueChanged:)
forControlEvents:UIControlEventValueChanged
];
动作方法示例:
-(void) sliderValueChanged: (id)sender
{
UISlider *control = (UISlider *) sender;
if (control == mySlider) {
float value = control.value;
// 响应滑块值的额外代码
}
}
如果你希望在滑块拖动时触发事件,可以将
continuous
属性设置为
YES
:
slider.continuous = YES;
5. 文本字段控件(Text Field Controls)
UITextField 类继承自 UIControl,可以使用 UIControl 类的许多属性来进一步定制其行为。
5.1 样式选项
| 属性 | 描述 |
|---|---|
| textAlignment |
指定控件内文本的对齐方式,可选值为
UITextAlignmentLeft
、
UITextAlignmentRight
、
UITextAlignmentCenter
,默认左对齐
|
| borderStyle |
指定文本控件周围边框的样式,可选值为
UITextBorderStyleNone
、
UITextBorderStyleLine
、
UITextBorderStyleBezel
、
UITextBorderStyleRoundedRect
,默认无边界。如果使用自定义背景图像,样式将被忽略
|
| placeholder |
为空文本字段绘制一个灰色占位符字符串,当文本字段未编辑且无值时显示,接受
NSString
对象
|
| clearsOnBeginEditing |
如果用户点击文本字段时应清除文本,将此布尔值设置为
YES
。默认情况下,文本字段将光标移动到点击位置,不删除文本
|
| adjustsFontSizeToFitWidth |
当设置为
YES
时,此属性会使文本自动缩小以适应文本窗口的大小。默认行为是保留原始字体大小,允许长文本滚动出视图
|
| background |
接受
UIImage
对象并将其设置为文本字段的背景,这会使
borderStyle
属性被忽略
|
| clearButtonMode |
定义清除按钮的行为,清除按钮是文本字段右侧的小 “X” 按钮,允许用户通过点击清除所有文本。默认值为
UITextFieldViewNever
,隐藏清除按钮。可选模式有
UITextFieldViewModeNever
、
UITextFieldViewModeWhileEditing
、
UITextFieldViewModeUnlessEditing
、
UITextFieldViewModeAlways
|
| LeftView, leftViewMode, rightView, rightViewMode |
这些属性允许你将
UIView
类的派生对象附加到文本字段的左右两侧。常见的是将
UIButton
对象(如放大镜或书签按钮)附加到文本字段。每个视图都有一个伴随的模式,你可以使用与
clearButtonmode
属性相同的值进行设置
|
5.2 渲染覆盖
除了样式选项,你可以为自定义
UITextField
对象添加许多不同的覆盖方法,这些方法会影响文本字段的渲染。这些方法返回一个
CGRect
结构,指定文本字段每个组件的边界。例如:
- (CGRect)clearButtonRectForBounds: (CGRect) bounds {
return CGRectMake(bounds.origin.x + bounds.size.x - 50,
bounds.origin.y + bounds.size.y - 20,
16, 16);
}
创建
UITextField
子类时可用的覆盖方法包括:
-
borderRectForBounds
:指定边界矩形
-
textRectForBounds
:指定显示文本的边界
综上所述,iOS 中的这些常见控件和事件处理机制为开发者提供了丰富的功能和灵活性,能够满足各种不同的应用需求。通过合理运用这些控件和机制,开发者可以创建出更加交互性强、用户体验好的应用程序。
iOS 常见控件与事件处理详解
6. 控件事件处理流程总结
为了更清晰地理解控件事件的处理流程,我们可以通过以下 mermaid 流程图来展示:
graph TD;
A[事件发生] --> B{是否注册监听};
B -- 是 --> C[调用对应 action 方法];
B -- 否 --> D[无操作];
C --> E[处理事件逻辑];
E --> F[更新 UI 或执行其他操作];
从这个流程图可以看出,当事件发生时,系统首先会检查该事件是否有注册监听。如果有注册,就会调用对应的 action 方法,在这个方法中处理事件逻辑,最后根据逻辑结果更新 UI 或执行其他操作;如果没有注册监听,则不会有任何操作。
7. 控件使用的注意事项
在使用这些常见控件时,有一些注意事项需要开发者牢记:
-
未文档化 API 的使用
:如在开关和滑块控件中提到的未文档化 API,虽然它们能提供一些额外的功能,但随时可能更改,并且使用未文档化 API 可能导致应用被 App Store 拒绝。因此,在开发过程中尽量避免使用,或者在投入生产前确保移除相关功能。
-
图像资源管理
:在分段控件和滑块控件中使用图像时,要注意将图像正确复制到 Xcode 项目的
Resources
文件夹中,以确保应用安装后能正常访问这些图像。同时,由于控件本身不会对图像进行缩放,所以在设计图像时要确保其适合按钮或控件的空间。
-
事件处理逻辑
:在为控件添加事件处理方法时,要确保逻辑清晰,避免出现逻辑混乱或错误。例如,在处理分段控件的
UIControlEventValueChanged
事件时,要正确判断控件对象,并根据选中的分段执行相应的操作。
8. 不同控件的应用场景分析
不同的控件适用于不同的应用场景,以下是一些常见的应用场景分析:
| 控件类型 | 应用场景 |
| — | — |
| 分段控件 | 当需要为用户提供有限数量的相关选择,且只能选择一个选项时,如设置主题风格(明亮模式、暗黑模式)、选择不同的分类(图片、视频、音频)等。 |
| 开关 | 用于简单的开/关功能,如开启或关闭通知、打开或关闭蓝牙等。 |
| 滑块 | 适用于需要用户调整数值范围的场景,如音量调节、亮度调节、进度控制等。 |
| 文本字段控件 | 当需要用户输入文本信息时,如登录界面的用户名和密码输入、搜索框输入关键词等。 |
9. 控件组合使用示例
在实际开发中,往往会将多个控件组合使用,以实现更复杂的功能。以下是一个简单的示例,展示了如何组合使用分段控件、开关和文本字段控件:
// 创建分段控件
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:@[@"选项1", @"选项2"]];
segmentedControl.selectedSegmentIndex = 0;
[segmentedControl addTarget:self action:@selector(segmentChanged:) forControlEvents:UIControlEventValueChanged];
// 创建开关
UISwitch *switchControl = [[UISwitch alloc] initWithFrame:CGRectMake(0, 50, 0, 0)];
[switchControl addTarget:self action:@selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
// 创建文本字段控件
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 100, 200, 30)];
textField.placeholder = @"请输入文本";
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.clearButtonMode = UITextFieldViewModeWhileEditing;
// 将控件添加到父视图
UIView *parentView = self.view;
[parentView addSubview:segmentedControl];
[parentView addSubview:switchControl];
[parentView addSubview:textField];
// 分段控件事件处理方法
- (void)segmentChanged:(id)sender {
UISegmentedControl *control = (UISegmentedControl *)sender;
NSLog(@"选中的分段是:%ld", (long)control.selectedSegmentIndex);
}
// 开关事件处理方法
- (void)switchChanged:(id)sender {
UISwitch *control = (UISwitch *)sender;
NSLog(@"开关状态:%@", control.isOn ? @"开启" : @"关闭");
}
在这个示例中,我们创建了一个分段控件、一个开关和一个文本字段控件,并将它们添加到父视图中。同时,为分段控件和开关添加了事件处理方法,当用户操作这些控件时,会在控制台输出相应的信息。
10. 总结与展望
iOS 中的常见控件如分段控件、开关、滑块和文本字段控件等,为开发者提供了丰富的交互方式。通过合理使用这些控件,并结合 UIControl 的事件通知机制,开发者可以创建出功能强大、用户体验良好的应用程序。
在未来的开发中,随着 iOS 系统的不断更新和发展,这些控件可能会有更多的功能和特性。同时,开发者也可以根据实际需求,进一步扩展和定制这些控件,以满足不同用户的需求。例如,开发自定义的分段控件样式、实现更复杂的滑块交互效果等。总之,掌握这些常见控件的使用和事件处理机制,是 iOS 开发中非常重要的基础。
iOS常见控件与事件解析
超级会员免费看
2015

被折叠的 条评论
为什么被折叠?



