簡單的數字鍵盤來示範客制化的動作. 這部份我想網路上已經有不少 sample code , 但大部份基本上都是
以 SDK 3.x 的版本去實作, 以"特定寫法"來實作客制化在 iOS4 會有問題, 這部份稍候會提到兩版本的差異.
上述看到的例子是 UIKeyboardTypeNumberPad 搭配 "Done" 的圖示所組合而成的. 在開
始介紹如何實作之前, 先稍微提一下網路上查到的一些範例寫法. 因為 SDK 升版之
後在架構上有做了些修改, 所以導致行為上的不正確. 以下面這例子為例, 它可以正
常的在 iOS4 之前的版本運行, 但在 iOS4 上卻會有看不到上面 "Done" 圖示的問題.
- (void)loadView{
...
textFieldContent.delegate = self;
textFieldContent.placeholder = @"press me";
textFieldContent.keyboardType = UIKeyboardTypeNumberPad;
textFieldContent.returnKeyType = UIReturnKeyDone;
[self.view addSubview:textFieldContent];
[textFieldContent release];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
}
- (void)keyboardWillShowOnDelay:(NSNotification *)notification{
UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
doneButton.frame = CGRectMake(0, 163, 106, 53);
doneButton.adjustsImageWhenHighlighted = NO;
[doneButton setImage:[UIImage imageNamed:@"DoneUp.png"] forState:UIControlStateNormal];
[doneButton setImage:[UIImage imageNamed:@"DoneDown.png"] forState:UIControlStateHighlighted];
[doneButton addTarget:self action:@selector(doneButton:) forControlEvents:UIControlEventTouchUpInside];
UIWindow* tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
UIView* keyboard;
for(int i=0; i<[tempWindow.subviews count]; i++) {
keyboard = [tempWindow.subviews objectAtIndex:i];
if([[keyboard description] hasPrefix:@"<UIKeyboard"] == YES)
[keyboard addSubview:doneButton];
}
}
上述這段代碼主要原理是透過跟 OS 註冊 keyboard 相關的 notification, 並在顯示
keyboard 時, 在 keyboard view 上添加所需要的特定 UIView, 簡單流程大致如下
1. 註冊 UIKeyboardWillShowNotification : 當 keyboard 要秀時, OS 就會呼叫
keyboardWillShow
2. 當被 keyboardWillShow 叫用時, 搜尋屬於 keyboard 的 view
if([[keyboard description] hasPrefix:@"<UIKeyboard"] == YES)
3. 當找到所需要的 view 時, 再將需要的 view 加入即可
[keyboard addSubview:doneButton];
上面就是一個 customized keyboard 的簡單實作流程. 但是為什麼這段 code 會無法
在 iOS4 上正確執行呢? 問題點主要出在上述的第 2 個步驟.
在舊的 SDK 中, 當 UIKeyboardWillShowNotification 事件發生且叫用 keyboardWillShow
時, 此時的 keyboard view 已經被添加到 windows 裡了, 但是在 iOS4 的世界中, 相同
情況發生時, keyboard view 卻會在下個 event loop 裡才會被添加到 windows 中, 也
就是因為如此, 所以上述
[[[UIApplication sharedApplication] windows] objectAtIndex:1];
會找不到 keyboard view. 除了這原因以外, 還有另一個重要的差異性, 第 2 步驟所比
對的 @"<UIKeyboard" 字串在 iOS4 中也被修正過, 它被藏在 @"<UIPeripheralHostView"
裡.
針對這兩點, 所以將只要將之修正即可正常的在 iOS4 上執行
1. keyboard view
既然知道是 keyboard view 會在下個 event loop 才會被放到 windows 裡, 所以我們
可以透過下面方式將 keyboardWillShow 延遲叫用
[self performSelector:@selector(keyboardWillShow:) withObject:nil afterDelay:0];
2. 修正比對 @"<UIKeyboard" 的方式
if ([[possibleKeyboard description] hasPrefix:@"<UIPeripheralHostView"])
possibleKeyboard = [[possibleKeyboard subviews] objectAtIndex:0];
if ([[possibleKeyboard description] hasPrefix:@"<UIKeyboard"])
{
foundKeyboard = possibleKeyboard;
break;
}
經過上述兩個修正之後的 code 大概會如下 :
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShowOnDelay:)
name:UIKeyboardWillShowNotification
object:nil];
- (void)keyboardWillShowOnDelay:(NSNotification *)notification
{
[self performSelector:@selector(keyboardWillShow:) withObject:nil afterDelay:0];
}
- (void)keyboardWillShow:(NSNotification *)notification
{
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;
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;
}
}
}
if (foundKeyboard)
{
// create custom button
UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
doneButton.frame = CGRectMake(0, 163, 106, 53);
doneButton.adjustsImageWhenHighlighted = NO;
[doneButton setImage:[UIImage imageNamed:@"DoneUp.png"] forState:UIControlStateNormal];
[doneButton setImage:[UIImage imageNamed:@"DoneDown.png"] forState:UIControlStateHighlighted];
[doneButton addTarget:self action:@selector(doneButton:) forControlEvents:UIControlEventTouchUpInside];
[foundKeyboard addSubview:doneButton];
}
}
這邊要注意到的是, 因為同一個 app 有可能會在新舊版本的 OS 上執行, 所以若只有
針對 iOS4 而做修改, 就有可能會造成舊 iPhone 無法正常值行, 有鑒於此, 上述這段
code 針對比對字串做了點小技巧, 讓此 code 可以符合新舊版本.
完整的範例可以到 這裡 下載
沒有留言:
張貼留言