25、iOS开发中的图像选择、键盘设置与选择器应用

iOS开发中的图像选择、键盘设置与选择器应用

1. 图像选择器(Image Picker)

1.1 图像源定义

可以使用 sourceType 属性来定义向用户展示的各种图像源,示例代码如下:

picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;

支持的图像源类型如下表所示:
| 类型 | 描述 |
| ---- | ---- |
| UIImagePickerControllerSourceTypePhotoLibrary | 照片库 |
| UIImagePickerControllerSourceTypeCamera | 相机 |
| UIImagePickerControllerSourceTypeSavedPhotosAlbum | 已保存的照片 |

1.2 图像编辑功能

若要允许用户按照自己的喜好移动和缩放图像,可通过将 allowsImageEditing 属性设置为 YES 来启用图像编辑功能,代码如下:

picker.allowsImageEditing = YES;

1.3 图像选择处理

当用户选择一张图片时,选择器的委托(delegate)会通过 didFinishPickingImage 方法得到通知。委托会接收到一个包含图像的 UIImage 对象,以及一个包含编辑属性的 NSDictionary 对象(如果启用了编辑功能)。
设置选择器的委托:

picker.delegate = self;

在委托类中添加以下方法以在用户选择图像时得到通知:

- (void)imagePickerController:(UIImagePickerController *)picker
    didFinishPickingImage:(UIImage *)image
    editingInfo:(NSDictionary *)editingInfo
{
    /* Code to handle image selection */
}

若用户取消图像选择,也希望得到通知,则可在委托中添加 imagePickerControllerDidCancel 方法:

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    /* Additional code to handle image selection canceled */
}

2. 键盘属性设置

2.1 键盘设计理念

当用户点击文本字段时,运行时会自动弹出键盘供用户输入。苹果的框架设计使得文本字段对键盘的行为拥有完全的控制权,而不是键盘对象本身。当键盘出现时,它会自动适应文本字段中定义的行为。

2.2 键盘样式

UI Kit框架支持八种不同的键盘样式,可使用文本对象的 keyboardType 方法为每个文本字段分配不同的样式,示例代码如下:

textView.keyboardType = UIKeyboardTypePhonePad;

支持的键盘样式如下表所示:
| 样式 | 描述 |
| ---- | ---- |
| UIKeyboardTypeDefault | 默认键盘:所有字符可用 |
| UIKeyboardTypeASCIICapable | 支持ASCII的默认键盘 |
| UIKeyboardTypeNumbersAndPunctuation | 标准电话键盘,支持 + * # 符号 |
| UIKeyboardTypeURL | 带有.COM按钮的URL键盘;仅支持URI字符 |
| UIKeyboardTypeNumberPad | 用于数字输入的数字键盘 |
| UIKeyboardTypePhonePad | 用于输入电话号码的电话键盘 |
| UIKeyboardTypeNamePhonePad | 也支持输入姓名的电话键盘 |
| UIKeyboardTypeEmailAddress | 用于输入电子邮件地址的键盘 |

2.3 键盘外观

除了键盘类型,还可以通过设置 keyboardAppearance 属性来调整键盘的外观,示例代码如下:

textView.keyboardAppearance = UIKeyboardAppearanceDefault;

可用的键盘外观如下表所示:
| 样式 | 描述 |
| ---- | ---- |
| UIKeyboardAppearanceDefault | 默认外观;浅灰色 |
| UIKeyboardAppearanceAlert | 深灰色/石墨色 |

2.4 返回键样式

对于带有返回键的键盘,可以使用文本对象的 returnKeyType 属性为返回键分配各种样式,示例代码如下:

textView.returnKeyType = UIReturnKeyGo;

支持的返回键样式如下表所示:
| 样式 | 描述 |
| ---- | ---- |
| UIReturnKeyDefault | 默认:灰色的“Return”按钮 |
| UIReturnKeyGo | 蓝色的“Go”按钮 |
| UIReturnKeyGoogle | 蓝色的“Google”按钮,用于搜索 |
| UIReturnKeyJoin | 蓝色的“Join”按钮 |
| UIReturnKeyNext | 灰色的“Next”按钮 |
| UIReturnKeyRoute | 蓝色的“Route”按钮 |
| UIReturnKeySearch | 蓝色的“Search”按钮 |
| UIReturnKeySend | 蓝色的“Send”按钮 |
| UIReturnKeyYahoo | 蓝色的“Yahoo!”按钮,用于搜索 |
| UIReturnKeyDone | 蓝色的“Done”按钮 |
| UIReturnKeyEmergencyCall | 紧急呼叫按钮 |

2.5 自动大写功能

键盘可以自动将新行或句子的首字母大写。可以通过设置文本对象的 autocapitalizationType 属性来切换此功能,示例代码如下:

textView.autocapitalizationType = UITextAutocapitalizationTypeNone;

支持的自动大写类型如下:
- UITextAutocapitalizationTypeNone
- UITextAutocapitalizationTypeWords
- UITextAutocapitalizationTypeSentences
- UITextAutocapitalizationTypeAllCharacters

2.6 自动更正功能

输入文本时,文本视图和键盘对象会协同工作,根据内部的常用误拼单词字典和记录用户自己输入的打字缓存,提供可能的打字错误更正。iPhone在 /private/var/mobile/Library/Keyboard/dynamic-text.dat 中生成字典。
自动更正功能默认启用,但可以使用文本视图的 autocorrectionType 属性来切换此功能,示例代码如下:

textView.autocorrectionType = UITextAutocorrectionTypeDefault ;

可用的自动更正类型如下:
- UITextAutocorrectionTypeDefault
- UITextAutocorrectionTypeNo
- UITextAutocorrectionTypeYes

2.7 安全文本输入

当在文本窗口中输入密码或其他私人数据时,这些信息不应被缓存在iPhone中。开启安全文本输入会禁用文本字段的自动更正和单词缓存功能。要激活安全文本模式,可设置 secureTextEntry 属性,示例代码如下:

textView.secureTextEntry = YES;

3. 选择器(Pickers)

3.1 选择器概述

选择器是iPhone上的滚轮控件,是大型的旋转拨盘,可以容纳任意数量的不同选项。选择器用于替代下拉菜单,为用户提供图形丰富的选择界面。 UIPickerView 类被设计为一个完整的视图类,而不是一个控件,这是由于其复杂性和占用的屏幕空间。这使得可以将选择器附加到其他视图或窗口上。

3.2 创建选择器

UIPickerView 类在屏幕上占用320×216像素的空间,但可以在窗口中垂直偏移。与表格类似, UIPickerView 类使用数据源;但与表格不同的是,选择器不使用索引路径,而是通过 NSInteger 值引用每一行。选择器可以有多个拨盘,每个拨盘称为一个组件。
创建选择器的示例代码如下:

UIPickerView *pickerView = [ [ UIPickerView alloc ]
    initWithFrame: CGRectMake(0.0, 280.0, 0.0, 0.0)];
pickerView.delegate = self;
pickerView.dataSource = self;

3.3 选择器属性设置

选择器视图的许多属性在SDK中已被私有化,开发者对其的控制不如内部类那么多。选择器有切换声音、进行多项选择和进行美学调整等可变选项,但这些接口对SDK开发者不可用。唯一可用的美学选项是选择窗口。
若要在当前选择上显示一个半透明窗口,可将选择器的 showsSelectionIndicator 属性设置为 YES ,示例代码如下:

pickerView.showsSelectionIndicator = YES;

3.4 选择器数据源方法

创建选择器视图后,必须编写数据源代码来提供有关选择器构造的信息。构建数据源需要实现以下方法,这些方法是 UIPickerViewDataSource 协议的必需组件:

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    A([开始]):::startend --> B(创建选择器视图):::process
    B --> C(实现数据源方法):::process
    C --> D(numberOfComponentsInPickerView):::process
    C --> E(numberOfRowsInComponent):::process
    D --> F(定义显示的组件数量):::process
    E --> G(返回指定组件的行数):::process
    F --> H(完成数据源配置):::process
    G --> H
    H --> I([结束]):::startend
  • numberOfComponentsInPickerView :定义选择器视图要显示的单个滚轮(列)的数量。
  • numberOfRowsInComponent :可以为选择器中的每个拨盘分配不同数量的可能值(行)。此方法应返回指定拨盘的总行数。

此外, UIPickerViewDelegate 协议实现了以下方法来获取有关选择器组件的特定信息:
- titleForRow :返回给定拨盘(组件)的给定行的实际拨盘值,这些值以 NSString 对象的形式返回。
- viewForRow :此方法可以覆盖选择器的默认行为,以在组件拨盘中显示任何 UIView 类。
- widthForComponent :返回给定组件(拨盘)的宽度。如果未实现此方法,选择器将自适应大小。
- rowHeightForComponent :返回给定组件(拨盘)的高度。如果未实现此方法,选择器将自适应大小。

3.5 显示选择器

创建并配置选择器视图并编写数据源方法后,就可以将选择器附加到视图控制器上,示例代码如下:

[ self.view addSubview: pickerView ];

3.6 读取选择器的选择

获取选择器视图中所选列索引的最直接方法是使用视图的 selectedRowInComponent 方法,示例代码如下:

int selectedRow = [ pickerView selectedRowInComponent: 0 ];

还有一个委托方法,每当用户在选择器视图中选择一行时,该方法会得到通知。可以使用此方法提醒一个对象,使其能够对新的行选择做出响应,示例代码如下:

pickerView.delegate = myObject;

要在拨盘的值更改时收到通知,可以在类中添加以下名为 didSelectRow 的委托方法:

- (void)pickerView:(UIPickerView *)pickerView
   didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    NSLog(@"Selected row %d from dial %d", row, component);
    /* Additional code to handle row selection */
}

3.7 鼻子选择器示例(NosePicker)

此示例向用户展示一个包含不同鼻子样式和大小的 UIPickerView 。首先创建一个视图控制器,然后将选择器视图作为子视图添加到该控制器中。用户可以滚动鼻子列表并选择一个。
以下是该示例的主要代码:

3.7.1 NosePickerAppDelegate.h
#import <UIKit/UIKit.h>
@class NosePickerViewController;
@interface NosePickerAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    NosePickerViewController *viewController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet NosePickerViewController *viewController;
@end
3.7.2 NosePickerAppDelegate.m
#import "NosePickerAppDelegate.h"
#import "NosePickerViewController.h"
@implementation NosePickerAppDelegate
@synthesize window;
@synthesize viewController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
    CGRect screenBounds = [ [ UIScreen mainScreen ] bounds ];
    self.window = [ [ [ UIWindow alloc ] initWithFrame: screenBounds ] autorelease ];
    viewController = [ [ NosePickerViewController alloc ] init ];
    [ window addSubview: viewController.view ];
    [ window makeKeyAndVisible ];
}
- (void)dealloc {
    [ viewController release ];
    [ window release ];
    [ super dealloc ];
}
@end
3.7.3 NosePickerViewController.h
#import <UIKit/UIKit.h>
@protocol UIPickerViewDataSource, UIPickerViewDelegate;
@interface NosePickerViewController : UIViewController <UIPickerViewDelegate,
 UIPickerViewDataSource> {
    UIPickerView *pickerView;
    UITextView *textView;
    NSMutableArray *noses;
    NSMutableArray *sizes;
    int selection[2];
}
- (void)updateText;
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;
- (NSInteger)pickerView:(UIPickerView *)pickerView
    numberOfRowsInComponent:(NSInteger)component;
- (NSString *)pickerView:(UIPickerView *)pickerView
    titleForRow:(NSInteger)row forComponent:(NSInteger)component;
- (void)pickerView:(UIPickerView *)pickerView
    didSelectRow:(NSInteger)row inComponent:(NSInteger)component;
@end
3.7.4 NosePickerViewController.m
#import "NosePickerViewController.h"
@implementation NosePickerViewController
- (id)init {
    self = [ super init ];
    if (self != nil) {
        noses = [ [ NSMutableArray alloc ] init ];
        [ noses addObject: @"Straight" ];
        [ noses addObject: @"Aquiline" ];
        [ noses addObject: @"Retrousse" ];
        [ noses addObject: @"Busque" ];
        [ noses addObject: @"Sinuous" ];
        [ noses addObject: @"Melanesian" ];
        [ noses addObject: @"African" ];
        sizes = [ [ NSMutableArray alloc ] init ];
        [ sizes addObject: @"Small" ];
        [ sizes addObject: @"Medium" ];
        [ sizes addObject: @"Large" ];
        [ sizes addObject: @"Super-Size" ];
        selection[0] = selection[1] = 0;
    }
    return self;
}
- (void)loadView {
    CGRect bounds = [ [ UIScreen mainScreen ] applicationFrame ];
    [ super loadView ];
    pickerView = [ [ UIPickerView alloc ]
        initWithFrame: CGRectMake(0.0, bounds.size.height - 216.0, 0.0, 0.0)
    ];
    pickerView.delegate = self;
    pickerView.dataSource = self;
    pickerView.showsSelectionIndicator = YES;
    [ self.view addSubview: pickerView ];
    textView = [ [ UITextView alloc ] initWithFrame:
        CGRectMake(0.0, 0.0, bounds.size.width, bounds.size.height - 216.0)
    ];
    textView.font = [ UIFont fontWithName: @"Arial" size: 18.0 ];
    textView.textAlignment = UITextAlignmentCenter;
    textView.editable = NO;
    [ self updateText ];
    [ self.view addSubview: textView ];
}
- (void)updateText {
    textView.text = [ NSString stringWithFormat:
        @"One %@, %@ schnoz:\nComing right up!\n",
        [ sizes objectAtIndex: selection[1] ],
        [ noses objectAtIndex: selection[0] ]
    ];
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
    return 2;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView
     numberOfRowsInComponent:(NSInteger)component
{
    switch(component) {
        case(0):
            return [ noses count ];
            break;
        case(1):
            return [ sizes count ];
            break;
    }
    return 0;
}
- (NSString *)pickerView:(UIPickerView *)pickerView
    titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    switch (component) {
        case(0):
            return [ noses objectAtIndex: row ];
            break;
        case(1):
            return [ sizes objectAtIndex: row ];
    }
    return nil;
}
- (void)pickerView:(UIPickerView *)pickerView
      didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    selection[component] = row;
    [ self updateText ];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:
    (UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)didReceiveMemoryWarning {
    [ super didReceiveMemoryWarning ];
}
- (void)dealloc {
    [ pickerView release ];
    [ noses release ];
    [ sizes release ];
    [ super dealloc ];
}
@end
3.7.5 main.m
#import <UIKit/UIKit.h>
int main(int argc, char *argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, @"NosePickerAppDelegate");
    [pool release];
    return retVal;
}

3.8 鼻子选择器示例流程分析

  1. 应用程序实例化时,会创建一个新的视图控制器,该控制器会初始化一个鼻子样式数组和一个鼻子大小数组,并为当前选择的拨盘初始化变量存储,存储在 selection 中。
  2. 当视图控制器的 loadView 方法被调用时,会创建 UIPickerView UITextView 对象,并将它们作为子视图添加到视图控制器中。选择器视图的委托和数据源被设置为视图控制器。控制器的 updateText 方法会被调用一次,以设置文本视图中的文本。
  3. UIPickerView 类的内部机制会调用其数据源,数据源会返回选择器视图中的组件数量、行数和每行的标题。
  4. 当用户在选择器视图的任何一个拨盘上选择一个新项时,视图的委托(即视图控制器)会通过 pickerView didSelectRow 方法得到通知。这会更新给定拨盘的最后选择行,并刷新文本显示,以反映当前选择的鼻子和大小组合。

4. 日期/时间选择器(Date/Time Pickers)

4.1 日期/时间选择器概述

UIDatePicker 类是一个控件,它封装并定制了 UIPickerView 类,专门用于接受日期、时间和持续时间输入。日期选择器会自动配置其列以符合指定的样式,因此在配置拨盘时无需进行底层工作,还可以为任何日期范围进行定制。
UIDatePicker 严重依赖 NSDate 类,该类是桌面Cocoa中使用的基础类集的一部分。可以在苹果开发者连接网站的在线Cocoa参考中找到有关此类的更多信息。为了便于示例,我们使用其最简单的方法 initWithString 来创建一个 NSDate 对象:

NSDate *myDate = [ [ NSDate alloc ]
    initWithString: @"1963-11-22 12:30:00 −0500" ];

4.2 创建日期/时间选择器

UIDatePicker 比标准的 UIPickerView 更简单,它会根据指定的日期范围构建自己的数据源。使用时只需创建对象即可,示例代码如下:

UIDatePicker *datePicker = [ [ UIDatePicker alloc ]
    initWithFrame: CGRectMake(0.0, 0.0, 0.0, 0.0)];

默认情况下,选择器会显示当前日期和时间,并显示星期几、月、日、小时、分钟和上午/下午的拨盘。用户默认可以选择任何日期或时间组合。

4.3 日期选择器模式

日期/时间选择器支持四种不同的选择模式,可以通过设置 datePickerMode 属性来定义模式,示例代码如下:

datePicker.datePickerMode = UIDatePickerModeTime;

支持的模式如下表所示:
| 模式 | 描述 |
| ---- | ---- |
| UIDatePickerModeTime | 小时、分钟和上午/下午选择 |
| UIDatePickerModeDate | 月、日和年 |
| UIDatePickerModeDateAndTime | 默认;星期几 + 月 + 日、小时、分钟和上午/下午选择 |
| UIDatePickerModeCountDownTimer | 用于计时器的小时和分钟显示 |

4.4 时间间隔设置

可以将分钟拨盘设置为以各种间隔显示分钟,只要该间隔能被60整除即可。默认情况下,分钟拨盘以一分钟的间隔显示。若要使用不同的间隔,可以将 minuteInterval 属性设置为所需的间隔,示例代码如下:

datePicker.minuteInterval = 10;

4.5 日期范围设置

可以通过设置 minimumDate maximumDate 属性来指定允许的日期范围。如果用户尝试滚动到超出此范围的日期,拨盘将滚动回最近的有效日期。这两个方法都期望传入一个 NSDate 对象,示例代码如下:

NSDate *minDate = [ [ NSDate alloc ]
    initWithString: @"1773-12-16 12:00:00 −0500" ];
NSDate *maxDate = [ [ NSDate alloc ]
    initWithString: @"1776-07-04 12:00:00 −0500" ];
datePicker.minimumDate = minDate;
datePicker.maximumDate = maxDate;

如果这两个日期范围属性中的一个或两个都未设置,默认行为将允许用户选择任何过去或未来的日期。例如,在选择生日时,生日可以是过去的任何日期,但上限为当前日期,这种设置就很有用。
若要设置默认显示的日期,可以设置 date 属性,示例代码如下:

datePicker.date = minDate;

也可以使用 setDate 方法。如果选择动画效果,拨盘将滚动到指定的日期,示例代码如下:

[ datePicker setDate: maxDate animated: YES ];

4.6 显示日期选择器

创建日期选择器后,可以使用与 UIPickerView 相同的方法将其附加到视图对象上,示例代码如下:

[ self addSubview: datePicker ];

无论传递给它的框架大小如何,选择器的高度始终为216像素,因此需要确保分配了足够的屏幕空间来容纳它。

4.7 日期/时间选择器使用流程

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    A([开始]):::startend --> B(创建NSDate对象):::process
    B --> C(创建UIDatePicker对象):::process
    C --> D(设置日期选择器模式):::process
    D --> E(设置时间间隔):::process
    E --> F(设置日期范围):::process
    F --> G(设置默认显示日期):::process
    G --> H(将日期选择器添加到视图):::process
    H --> I([结束]):::startend

5. 总结与拓展

5.1 功能总结

本文详细介绍了iOS开发中图像选择器、键盘属性设置、选择器以及日期/时间选择器的使用方法。图像选择器可以让用户从不同的图像源中选择图像,并支持图像编辑功能;键盘属性设置提供了丰富的自定义选项,包括键盘样式、外观、返回键样式、自动大写、自动更正和安全文本输入等;选择器和日期/时间选择器为用户提供了直观的选择界面,方便用户进行各种选项和日期时间的选择。

5.2 拓展建议

  • 图像选择器拓展 :可以结合图像裁剪、滤镜等功能,进一步丰富图像编辑体验;还可以实现图像的上传和分享功能。
  • 键盘属性拓展 :可以根据不同的应用场景,动态调整键盘的样式和属性,以提高用户输入的效率和体验。
  • 选择器拓展 :可以使用 UIPickerView.h 原型中提供的替代数据源方法,返回 UIView 对象而不是 NSString 对象,从而创建一组自定义的 UIImageView 对象用于选择器。
  • 日期/时间选择器拓展 :可以结合日历视图,让用户更直观地选择日期;还可以实现日期时间的计算和提醒功能。

通过对这些功能的深入理解和灵活运用,可以开发出更加丰富、易用的iOS应用程序。希望本文能为iOS开发者在UI设计和用户交互方面提供有价值的参考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值