通常有可能使用保持鍵盤上面的一個觀點,因爲它以動畫到位兩種方法。如您所知,首先是偵聽UIKeyboardWillShowNotification
並在userData中使用伴隨的持續時間/曲線/幀值來幫助您在鍵盤上方定位和製作視圖的動畫。
第二種方法是爲調用鍵盤的視圖(UITextField
,在這裏)提供inputAccessoryView
。 (我意識到這不會提供你要求的效果,一旦鍵盤運行到工具欄/文本框就會「推動」工具欄/文本框,但後面會詳細介紹) iOS將把inputAccessoryView保存爲也可以將父母的鍵盤和父母聯繫起來。根據我的經驗,這提供了最好看的動畫。我不認爲我曾經使用UIKeyboardWillShowNotification
方法完成完美動畫,尤其是現在在iOS7中,在鍵盤動畫的末尾有一些反彈。 UIKit Dynamics也可能會將此反彈應用於您的視圖,但將其與鍵盤完全同步會很困難。
以下是我在過去爲類似於您的場景所做的:底部定位UIToolbar
在customView欄按鈕項中有UITextField
用於輸入。在你的情況下,這是定位在UITabBar
以上。該ITextField
有一個自定義inputAccessoryView
集,這是另一個UIToolbar
與另一個UITextField
。
當用戶點擊文本字段併成爲第一響應者時,鍵盤將第二個工具欄/文本字段與其一起移動到位(並且此轉換看起來非常好!)。當我們注意到發生這種情況時,我們將firstResponder從第一個文本字段轉換爲第二個,這樣一旦鍵盤就位,它就會有閃爍的插入符號。
當你決定結束編輯時,該怎麼做。首先,您必須在第二個文本字段中放棄第一個響應者,但如果您不小心,系統會將第一個響應者狀態傳遞迴原始文本字段!所以你必須防止這種情況發生,因爲否則你將處於一個無限循環中傳遞第一響應者,並且鍵盤永遠不會解散。其次,您需要將任何輸入到第二個文本字段的文本反射回第一個文本字段。
下面是這個方法的代碼:
@implementation TSViewController
{
IBOutlet UIToolbar* _toolbar; // parented in your view somewhere
IBOutlet UITextField* _textField; // the customView of a UIBarButtonItem in the toolbar
IBOutlet UIToolbar* _inputAccessoryToolbar; // not parented. just owned by the view controller.
IBOutlet UITextField* _inputAccessoryTextField; // the customView of a UIBarButtonItem in the inputAccessoryToolbar
}
- (void) viewDidLoad
{
[super viewDidLoad];
_textField.delegate = self;
_inputAccessoryTextField.delegate = self;
_textField.inputAccessoryView = _inputAccessoryToolbar;
}
- (void) textFieldDidBeginEditing: (UITextField *) textField
{
if (textField == _textField)
{
// can't change responder directly during textFieldDidBeginEditing. postpone:
dispatch_async(dispatch_get_main_queue(), ^{
_inputAccessoryTextField.text = textField.text;
[_inputAccessoryTextField becomeFirstResponder];
});
}
}
- (BOOL) textFieldShouldBeginEditing: (UITextField *) textField
{
if (textField == _textField)
{
// only become first responder if the inputAccessoryTextField isn't the first responder.
return ![_inputAccessoryTextField isFirstResponder];
}
return YES;
}
- (void) textFieldDidEndEditing: (UITextField *) textField
{
if (textField == _inputAccessoryTextField)
{
_textField.text = textField.text;
}
}
// invoke this when you want to dismiss the keyboard!
- (IBAction) done: (id) sender
{
[_inputAccessoryTextField resignFirstResponder];
}
@end
還有最後一個可能性,我能想到的。上面的方法有兩個獨立的工具欄/文本框的缺點。理想情況下,你需要的只是其中的一組,並且你希望看起來鍵盤會「推」它們(或將它們拉下來)。在現實中,動畫速度足夠快,我不認爲大多數人會注意到上述方法有兩套,但也許你不喜歡那樣..
這最後的方法是監聽鍵盤顯示/隱藏,並使用CADisplayLink
同步動畫工具欄/文本字段,因爲它實時檢測鍵盤位置的變化。在我的測試中,它看起來不錯。我看到的主要缺點是工具欄的位置稍微滯後。我正在使用自動佈局,轉換到傳統的框架定位可能會更快。另一個缺點是對鍵盤視圖層次結構的依賴性沒有顯着改變。這可能是最大的風險。
這還有一個竅門。工具欄使用約束條件定位在我的故事板中。距離視圖底部的距離有兩個限制。一個綁定到IBOutlet「_toolbarBottomDistanceConstraint」,這是代碼用於移動工具欄的內容。這個約束是一個「垂直空間」約束與「平等」關係。我將優先級設置爲500.有一個「大於或等於」關係的第二個平行「垂直空間」約束。這個常量是視圖底部的最小距離(例如,在標籤欄上方),優先級爲1000.通過這兩個約束,我可以將工具欄從底部距離設置爲任意值I像,但它永遠不會低於我的最低價值。這是使鍵盤看起來像推/拉工具欄,但讓它在某個點「放棄」動畫的關鍵。
最後,也許您可以將此方法與您已有的方法混合使用:使用CADisplayLink回調來檢測鍵盤何時「進入」您的工具欄,然後手動定位剩餘工具欄的動畫,使用真正的UIView動畫來爲你的工具欄設置動畫。您可以將持續時間設置爲鍵盤顯示動畫持續時間減去已經發生的時間。
@implementation TSViewController
{
IBOutlet UITextField* _textField;
IBOutlet UIToolbar* _toolbar;
IBOutlet NSLayoutConstraint* _toolbarBottomDistanceConstraint;
CADisplayLink* _displayLink;
}
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
}
- (void) viewDidLoad
{
[super viewDidLoad];
[self.view addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(dismiss:) ]];
_textField.inputAccessoryView = [[UIView alloc] init];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(keyboardWillShowHide:)
name: UIKeyboardWillShowNotification
object: nil];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(keyboardWillShowHide:)
name: UIKeyboardWillHideNotification
object: nil];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(keyboardDidShowHide:)
name: UIKeyboardDidShowNotification
object: nil];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(keyboardDidShowHide:)
name: UIKeyboardDidHideNotification
object: nil];
}
- (void) keyboardWillShowHide: (NSNotification*) n
{
_displayLink = [CADisplayLink displayLinkWithTarget: self selector: @selector(tick:)];
[_displayLink addToRunLoop: [NSRunLoop currentRunLoop] forMode: NSRunLoopCommonModes];
}
- (void) keyboardDidShowHide: (NSNotification*) n
{
[_displayLink removeFromRunLoop: [NSRunLoop currentRunLoop] forMode: NSRunLoopCommonModes];
}
- (void) tick: (CADisplayLink*) dl
{
CGRect r = [_textField.inputAccessoryView.superview.layer.presentationLayer frame];
r = [self.view convertRect: r fromView: _textField.inputAccessoryView.superview.superview];
CGFloat fromBottom = self.view.bounds.size.height - r.origin.y;
_toolbarBottomDistanceConstraint.constant = fromBottom;
}
- (IBAction) dismiss: (id) sender
{
[self.view endEditing: YES];
}
@end
這裏的視圖層次和約束:
如果任何人使用約束...可能是這個解決方案幫助他們... http://stackoverflow.com/questions/31356293/uitableview-and-uiview-with-keyboardwillshow/31356527#31356527 –