A.) 为了实现与 Apple Notes 滚动 + 键盘关闭类似的效果,我首先在 UIScrollView 中添加了一个 UITextView。
B.) 然后添加 self 作为键盘变化的观察者:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewDidBeginEditing:) name:UITextViewTextDidBeginEditingNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
C.) 然后当用户点击 textview / textfield 时,调用下面的方法。您获取键盘的开始高度和结束高度,并将名为keyboardHeight 的变量设置为endHeight 值(稍后使用)。
当用户上下移动自动更正/建议栏时,下面计算的“差异”用于上下移动文本。如果您不希望这样,您可以将 textView 上的“autocorrectionType”设置为 false。
-(void)keyboardWillChangeFrame:(NSNotification *)n {
float beginHeight = [[n.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size.height;
float endHeight = [[n.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
float difference = beginHeight-endHeight;
keyBoardHeight = endHeight; //set the var
//animate change
if (difference != 0){ //animate frame change in your textview }
}
D.) 在 textViewDidBegin 方法上,将 UIScrollview 移动到屏幕顶部,使 textview 与顶部齐平(setContentOffset)。
您计算 textview 的高度,因为它应该在视图顶部和键盘顶部之间,下面称为“initialTVHeight”。
您应该强制 textview 启用其滚动,因此将 textView.contentSize 设置为最小尺寸 (initialTVHeight) + 一个像素 - 这会强制滚动。
-(void)textViewDidBeginEditing:(UITextView *)textView {
//need to move the tv up to the top
float yOff = 0;
yOff += durationCell.frame.size.height;
yOff += reminderCell.frame.size.height;
yOff += fixedCell.frame.size.height;
yOff += repeatCell.frame.size.height;
[mainScroller setContentOffset:CGPointMake(0, yOff) animated:true];
//resize the textview to meet the top of the keyboard
float padding = 0; //padding between keyboard and last line in the textview
initialTVHeight = h - 60 - keyBoardHeight - padding; //the height when text does not overflow
textTV.frame = CGRectMake(0, textTV.frame.origin.y, w, initialTVHeight); //set the frame to that size
//if smaller than minimum, increase (if editing existing text)
if (textTV.contentSize.height < initialTVHeight){
textTV.contentSize = CGSizeMake(w, initialTVHeight+1); //force initial scroll
}
}
E.) 此方法将 textView contentSize 更新为最小高度以确保启用滚动(即,如果只有两行文本,用户仍然可以反弹滚动)。textView 内容长于初始大小的地方,让它自然增长。
-(void)textViewDidChange:(UITextView *)textView {
//require minimum height for scroll
if (textTV.contentSize.height < initialTVHeight){ //content height comes in under, force scroll
textTV.contentSize = CGSizeMake(w, initialTVHeight+1); //adding one forces scroll
}
}
F.) 添加这些方法,以确保仅通过用户拖动(而不是用户输入新行)关闭键盘
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
if ([scrollView isEqual:textTV]){
enableDragDismiss = true;
}
}
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
if ([scrollView isEqual:textTV]){
enableDragDismiss = false;
}
}
G.) 最后,添加这个方法,如果用户拖动到键盘高度以下,它会关闭键盘。
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (enableDragDismiss && [scrollView isEqual:textTV]){
float y = [textTV.panGestureRecognizer locationInView:self.view].y;
float keyboardY = h-keyBoardHeight;
if (y > keyboardY){
enableDragDismiss = false; //allow only once
[textTV resignFirstResponder];
[UIView animateWithDuration:0.5f
delay:0.0f
usingSpringWithDamping:1.0f
initialSpringVelocity:0.8f
options:UIViewAnimationOptionCurveEaseOut
animations:^{
mainScroller.contentOffset = CGPointMake(0, 0);
textTV.contentOffset = CGPointMake(0, 0);
}
completion:^(BOOL finished){
}];
float yOff = 60;
yOff += durationCell.frame.size.height;
yOff += reminderCell.frame.size.height;
yOff += fixedCell.frame.size.height;
yOff += repeatCell.frame.size.height;
textTV.frame = CGRectMake(0, textTV.frame.origin.y, w, h-yOff);
}
}
}