管理键盘 <- iOS文本编程指南

当用户点击文本字段、文本视图、或者web视图的字段的时候,系统会显示键盘。你可以使用键盘的多中属性来配置键盘的显示样式。在编辑会话开始及结束的时候,你还可以管理键盘。因为键盘会遮挡你正在编辑的视图,所以管理包括了调整用户界面抬高关注的区域,以便让它显示在键盘之上。

键盘和输入法

无论用户在何时点击对象都有接受文本输入的能力,该对象询问系统来显示适当的键盘。基于应用程序的需要和用户的语言首选项,系统可以显示多中不同的键盘中的一种。虽然app不能控制用户的语言首选项(以及因此导致的键盘的输入法),但是它可以控制它打算使用的键盘属性,例如配置任意的特定键及其行为。

为文本对象配置键盘

你可以通过app的文本对象来直接配置键盘的属性。UITextField和UITextView类都遵守UITextInputTraits协议,它定义了用于配置键盘的属性。通过编程的方式或者在Interface Builder检查器窗口设置这些属性,可以让系统显示特定类型的键盘。

默认的键盘配置是为普通文本输入设计的。图4-1显示了使用不同键盘设置的默认键盘。默认键盘在开始的时候显示字母键盘,但用户也可以把它切换到数字或者标点(punctuation)键盘。大多数其他键盘提供与默认键盘相似的功能,同时也提供额外的特定适配按钮来针对特殊任务。但是电话和数字键盘提供显著不同的布局,用以数字输入。

图 4-1 几种不同的键盘样式

Several different keyboard types
Several different keyboard types

想要实现不同用户的语言首选项,iOS还提供不同输入法和键盘布局来对应不同的语言,它们中的一些显示在图 4-2中。输入法和键盘布局取决于用户的语言首选项。其中一些键盘的输入是在多个阶段中进行的。

图 4-2 几种不同键盘和输入法

Several different keyboards and input methods

为web视图配置键盘

你可以为文本输入元素配置一些键盘属性。例如,你可以在输入元素的认定中包括自动纠错和自动大写属性,以指定键盘的行为,就像在下面的例子中所显示的那样。

<input type="text" size="30" autocorrect="off" autocapitalize="on">

你还可以控制用户点击web页中的文本字段的时候出现的键盘的类型。要想显示电话键盘、email键盘、或者URL键盘,分别给输入元素的类型属性使用tel、email、或url关键字。想要显示数字键盘,将模型属性值设置为" [0-9]* "或" \d* "。这些关键字和模型属性是HTML5的一部分,并且在iOS中可用。下面这张表显示了每个键盘类型如何显示,包括标准的键盘。
Text: <input type="text"></input>
Telephone: <input type="tel"></input>
URL: <input type="url"></input>
Email: <input type="email"></input>
Zip code: <input type="text" pattern="[0-9]* "></input>

管理键盘

尽管很多UIKit对象在用户交互的时候自动显示键盘,但app仍然有责任配置和管理键盘。下面这部分就是描述这些责任。

接受键盘通知

当键盘显示或隐藏时,iOS发送下面的通知给任何注册的观察者:

  • UIKeyboardWillShowNotification
  • UIKeyboardDidShowNotification
  • UIKeyboardWillHideNotification
  • UIKeyboardDidHideNotification

每个键盘通知包括了关于键盘在屏幕中的尺寸和位置的信息。你可以使用UIKeyboardFrameBeginUserInfoKey 和 UIKeyboardFrameEndUserInfoKey 键从每个通知的userInfo字典中访问这些信息;前者提供键盘开始时的frame,后者提供键盘结束时的frame(均在屏幕坐标内)。你应该始终使用这些通知中的信息,而不是假设键盘的尺寸或位置。不同输入法之间的尺寸是不能保证相同的。而且在每个iOS的发布版本之间也是不同的。甚至在相同版本相同的语言的情况下,键盘的的尺寸还基于app的方向。例如,图4-3 显示的在肖像和风景模式中URL键盘的相对尺寸。使用键盘通知的内置信息确保你始终拥有正确的尺寸和位置信息。

图 4-3 在肖像和风景模式中键盘的相对尺寸

Relative keyboard sizes in portrait and landscape modes
Relative keyboard sizes in portrait and landscape modes

注意:包含在userInfo字典的UIKeyboardFrameBeginUserInfoKey 和 UIKeyboardFrameEndUserInfoKey 属性中的矩形,应该只使用它所包含的尺寸信息。在矩形交互操作中不要使用矩形的原点(它始终为{0.0, 0.0})。因为键盘是同台的进入位置,键盘的实际边框矩形随时改变。

使用键盘通知的一个原因,是你可以在键盘出现的时候重定位被键盘遮挡的内容。关于如何处理该脚本(scenario)的信息,参见“移动在键盘下的内容”。

键盘通知的时间和视图控制器转换的时间之间没有定义关系。

显示键盘

当用户点击视图,系统自动注册该视图为第一响应者。当它正好是包含可编辑文本的视图时,该视图回味该文本开启一个编辑会话。在编辑会话开始的时候,如果键盘还没有显示,视图要求系统显示键盘。如果键盘已经显示,那么第一响应者的更改会导致文本输入从键盘重定向到新点击的视图。

因为键盘是在视图成为第一响应者的时候自动显示的,所以你往往不需要做任何事来显示它。但是,你可以通过调用视图的becomeFirstResponder方法以编程的方式显示键盘。调用这个方法把目标视图设置为第一响应者,并可以像用户点击了视图那样开始编辑进程。

如果app在单个屏幕上管理多个基于文本的视图,用当前的第一响应者来追踪视图是一个好办法,这会让你可以在稍后关闭键盘。

关闭键盘

虽然通常键盘显示是自动的,但是系统不会自动的关闭键盘。这需要app在合适的时候来负责关闭。通常,你要在用户动作的响应中完成此操作。例如,当用户点击键盘上的回车键或者完成键,或者点击app界面的其他按钮来取消键盘。基于你对键盘的配置,你或许需要添加额外的控制到用户界面,来促使键盘的关闭。

想要关闭键盘,你可以调用是当前第一响应者的基于文本的视图的resignFirstResponder方法。当是文本视图注销它的第一响应者状态的时候,它结束当前的编辑会话,通知它的委托,并关闭键盘。换句话说,如果你有一个被称为myTextField的UITextField的对象是当前的第一响应者,想要关闭键盘只需做如下操作:

[myTextField resignFirstResponder];

从这一刻开始的所有处理,都有文本对象自动完成。

移动在键盘下的内容

当要求显示键盘的时候,系统会从屏幕的地步滑入键盘,并覆盖在应用的内容上面。因为它在内容的顶层,所以有可能遮挡住用户想编辑的文本对象。当这种情况发生的时候,你必须调整你的内容,以便目标对象可见。

调整内容通常涉及到临时调整一个或多个视图的尺寸并定位它们,以便文本对象保持可见。最简单的方法是把使用键盘的文本对象嵌套在UIScrollView对象里面(或者它的子类中,例如UITableView)。当键盘显示的时候,你所需要做的指示重置滚动视图的内容区域,并把文本对象滚动到想要的位置。因此,在对UIKeyboardDidShowNotification的响应中,你的处理程序方法要执行如下操作:

  1. 获得键盘的尺寸。
  2. 根据键盘的高度,调整插入到滚动视图地底部内容。
  3. 滚动目标文本字段到视图中。

注意:对于UITableViewController类来说,当在行内编辑文本字段的时候,它会自动重调尺寸并重定位表视图。请阅读 Table View Programming Guide for iOS中的View Controllers 和 Navigation-Based Apps。

图4-4 用一个简单例子说明了前面步骤的,例子中UIScrollView对象嵌入了多个文本字段。当键盘出现的时候,通知处理程序方法调整滚动视图的内容和滚动指示器,然后使用UIScrollView的scrollRectToVisible:animated:方法来把点击的文本字段(本例中是email字段)滚动到视图中。

图 4-4 调整内容以容纳键盘

Adjusting content to accommodate the keyboard
Adjusting content to accommodate the keyboard

代码清单4-1 展示了注册键盘通知的代码,也展示了这些方法的处理程序方法。该代码通过管理滚动视图的视图控制器实现,并且滚动视图变量是一个outlet,它指向一个滚动视图对象。keyboardWasShown: 方法从该通知的info字典中得到键盘的尺寸,并且根据键盘的高度来调整滚动视图的底部插入内容。它还设置相同的值给滚动视图的scrollIndicatorInsets属性,以便滚动指示器不被键盘隐藏。注意,keyboardWillBeHidden:方法不使用键盘尺寸;它只是简单的将滚动视图的contentInset和scrollIndictorInsets属性设置为默认值,UIEdgeInsetsZero。

如果活动的文本字段被键盘隐藏,keyboardWasShown: 方法适当调整滚动视图的内容偏移。活动字段被存储在一个自定义变量中(在本例中被称为activeField),该变量是视图控制器的成员变量,并且在textFieldDidBeginEditing: 委托方法中设置,如代码清单4-2所示。(在这个例子中,视图控制器还做为文本字段的委托。)

代码清单 4-1 处理键盘的通知

// Call this method somewhere in your view controller setup code.

- (void)registerForKeyboardNotifications

{

    [[NSNotificationCenter defaultCenter] addObserver:self

            selector:@selector(keyboardWasShown:)

            name:UIKeyboardDidShowNotification object:nil];



   [[NSNotificationCenter defaultCenter] addObserver:self

             selector:@selector(keyboardWillBeHidden:)

             name:UIKeyboardWillHideNotification object:nil];



}



// Called when the UIKeyboardDidShowNotification is sent.

- (void)keyboardWasShown:(NSNotification*)aNotification

{

    NSDictionary* info = [aNotification userInfo];

    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;



    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);

    scrollView.contentInset = contentInsets;

    scrollView.scrollIndicatorInsets = contentInsets;



    // If active text field is hidden by keyboard, scroll it so it's visible

    // Your app might not need or want this behavior.

    CGRect aRect = self.view.frame;

    aRect.size.height -= kbSize.height;

    if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {

        [self.scrollView scrollRectToVisible:activeField.frame animated:YES];

    }

}



// Called when the UIKeyboardWillHideNotification is sent

- (void)keyboardWillBeHidden:(NSNotification*)aNotification

{

    UIEdgeInsets contentInsets = UIEdgeInsetsZero;

    scrollView.contentInset = contentInsets;

    scrollView.scrollIndicatorInsets = contentInsets;

}

代码清单 4-2 展示了一些额外的代码,它通过视图控制器用于设置并清除之前例子中的activeField变量。在初始化期间,每个在界面中文本字段设置视图控制器作为它的委托。因此,当文本字段激活时,它可以调用这些方法。更多关于文本字段和它的委托通知的信息,参见 “管理文本字段和文本视图”。

代码清单 4-2 跟踪活动文本字段的额外方法

- (void)textFieldDidBeginEditing:(UITextField * )textField

{

    activeField = textField;

}



- (void)textFieldDidEndEditing:(UITextField *)textField

{

    activeField = nil;

}

你还有几种方式可以让滚动视图中的编辑区域位于键盘的上方。除了改变滚动视图的底部内容插入以外,你可以通过键盘的高度来扩展内容视图的高度,然后滚动编辑的文本对象到视图中。虽然你可以为此目的设置UIScrollView类有contentSize属性,但你还可以调整内容视图的frame,就像代码清单4-3中所示那样。这段文档也适用了setContentOffset:animated: 方法来滚动编辑字段到视图,这种情况下,它刚刚把它滚动到键盘之上。

代码清单4-3 调整内容视图的frame并把字段滚动到键盘之上

- (void)keyboardWasShown:(NSNotification*)aNotification {

    NSDictionary* info = [aNotification userInfo];

    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    CGRect bkgndRect = activeField.superview.frame;

    bkgndRect.size.height += kbSize.height;

    [activeField.superview setFrame:bkgndRect];

    [scrollView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height) animated:YES];

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,646评论 4 366
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,979评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,391评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,356评论 0 215
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,740评论 3 293
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,836评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,022评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,764评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,487评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,728评论 2 252
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,200评论 1 263
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,548评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,217评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,134评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,921评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,919评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,766评论 2 274

推荐阅读更多精彩内容