对iOS系统键盘的hack以及注意事项
本文写于iOS5时代,后面几个版本的iOS版本对自带控件的view结构做了很大的变化,所以不适用了。
建议少用这类的hack方法,以保证iOS更新迭代的时候不出问题。
在做东方财富通新版的时候,需求组给出的新的需求是,数字键盘使用我们自己做的,而字母键盘使用系统自带的键盘,然而这里出现的一个问题就是,系统键盘进行输入法切换的时候是没有办法切换到自带的键盘中去的。这时候就需要对系统自带键盘进行hack。
原理很简单,就是在系统键盘弹出来时找到系统键盘所在的UIView,然后贴上自己的按钮覆盖掉原先的按钮。难点在于如何找到系统键盘所在的View。
效果图:
从效果图上可见,原先系统键盘的123和地球的图标被替换成了自定义的按钮。
做法:首先在当前的ViewController中监听:UIKeyboardDidShowNotification
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
然后自己实现keyboardDidShow方法,在里面根据需要调用下面hackSystemKeyboard方法:
- (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方法:
- (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的时候进行一次清理即可。
本著作係採用創用 CC 姓名標示 2.0 通用版 授權條款授權.