原文转载自:http://hikui.is-programmer.com/posts/35019.html
对iOS系统键盘的hack以及注意事项
在做东方财富通新版的时候,需求组给出的新的需求是,数字键盘使用我们自己做的,而字母键盘使用系统自带的键盘,然而这里出现的一个问题就是,系统键盘进行输入法切换的时候是没有办法切换到自带的键盘中去的。这时候就需要对系统自带键盘进行hack。
原理很简单,就是在系统键盘弹出来时找到系统键盘所在的UIView,然后贴上自己的按钮覆盖掉原先的按钮。难点在于如何找到系统键盘所在的View。
效果图:
从效果图上可见,原先系统键盘的123和地球的图标被替换成了自定义的按钮。
做法:首先在当前的ViewController中监听:UIKeyboardDidShowNotification
1
|
[[
NSNotificationCenter
defaultCenter]addObserver:
self
selector:
@selector
(keyboardDidShow:) name:UIKeyboardDidShowNotification object:
nil
];
|
然后自己实现keyboardDidShow方法,在里面根据需要调用下面hackSystemKeyboard方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
- (
void
)hackSystemKeyboard
{
UIView *foundKeyboard = [
self
getSystemKeyboard];
if
(foundKeyboard) {
//如果有原先存在的hack button,删之
[
self
clearKeyboardHack];
//hackButton 为123button
//新建hackButton,根据orentation定义不同的frame
UIButton *hackButton = [UIButton buttonWithType:UIButtonTypeCustom];
hackButton.backgroundColor = [UIColor clearColor];
hackButton.tag = 19100;
if
(
self
.isLandscape) {
hackButton.frame = CGRectMake(3, 124, 90, 38);
UIImage *btnBG = [UIImage imageNamed:@
"hackButtonLandscape.png"
];
[hackButton setBackgroundImage:btnBG forState:UIControlStateNormal];
}
else
{
hackButton.frame = CGRectMake(2, 173, 77, 43);
UIImage *btnBG = [UIImage imageNamed:@
"hackButton.png"
];
[hackButton setBackgroundImage:btnBG forState:UIControlStateNormal];
}
[hackButton setShowsTouchWhenHighlighted:
YES
];
[hackButton addTarget:
self
action:
@selector
(switchToNumberPad:) forControlEvents:UIControlEventTouchUpInside];
[foundKeyboard addSubview:hackButton];
}
}
|
这里要注意的是,如果这个ViewController支持横屏,则需要准备两套button图片。并且在willAnimateRotationToInterfaceOrientation中需要调用hackSystemButton这个方法。
里面比较重要的是getSystemKeyboard方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
- (UIView *)getSystemKeyboard
{
UIView *foundKeyboard =
nil
;
UIWindow *keyboardWindow =
nil
;
for
(UIWindow *testWindow in [[UIApplication sharedApplication] windows])
{
if
(![[testWindow
class
] isEqual:[UIWindow
class
]])
{
keyboardWindow = testWindow;
break
;
}
}
if
(!keyboardWindow)
return
nil
;
for
(UIView *possibleKeyboard in [keyboardWindow subviews])
{
//iOS3
if
([[possibleKeyboard description] hasPrefix:@
"<UIKeyboard"
])
{
foundKeyboard = possibleKeyboard;
break
;
}
else
{
// iOS 4 sticks the UIKeyboard inside a UIPeripheralHostView.
if
([[possibleKeyboard description] hasPrefix:@
"<UIPeripheralHostView"
])
{
possibleKeyboard = [[possibleKeyboard subviews] objectAtIndex:0];
}
if
([[possibleKeyboard description] hasPrefix:@
"<UIKeyboard"
])
{
foundKeyboard = possibleKeyboard;
break
;
}
}
}
return
foundKeyboard;
}
|
这里利用了iOS系统组件的Description进行View的判断,iOS 4以后的版本和之前的版本不一样,新版本中把UIKeyboard放在UIPeripheralHostView中。
最后需要注意的是,一个系统键盘在一个应用程序里面是共享的,所以如果这个ViewController中对键盘进行了hack,而在另外一个ViewController中不需要hack,那么需要在本ViewController退出的时候把Hack清理掉。但是在ViewWillDisappear中,我发现getSystemKeyboard方法寻找到的View并不是真正的keyboard,我的一个变通的办法就是在所有会导致ViewWillDisappear的步骤中插入clearKeyboardHack方法。
101年10月17日更新:
清理hack的时机应该是键盘将要隐藏前。只要在NotificationCenter中注册名为UIKeyboardWillHideNotification,收到notification的时候进行一次清理即可。