我有一个包含UITextView
的UIViewCOntroller
。当键盘出现时,我像这样调整它的大小:
#pragma mark - Responding to keyboard events
- (void)keyboardDidShow:(NSNotification *)notification
{
NSDictionary* info = [notification userInfo];
CGRect keyboardSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect newTextViewFrame = self.textView.frame;
newTextViewFrame.size.height -= keyboardSize.size.height + 70;
self.textView.frame = newTextViewFrame;
self.textView.backgroundColor = [UIColor yellowColor];
}
- (void)keyboardWillHide:(NSNotification *)notification
{
NSDictionary* info = [notification userInfo];
CGRect keyboardSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect newTextViewFrame = self.textView.frame;
newTextViewFrame.size.height += keyboardSize.size.height - 70;
self.textView.frame = newTextViewFrame;
}
textView似乎调整到了正确的大小,但当用户键入时,光标最终会“离开”textView框架。如下图所示:
黄色区域是UITextView
帧(我不知道R键旁边的蓝线是什么)。我发现这是相当复杂的。如果有什么不同的话,我使用的是iOS7。
有什么想法或小贴士吗?
更新
我有一个UITextView子类,它用下面的方法绘制水平线(如果有什么不同的话):
- (void)drawRect:(CGRect)rect {
//Get the current drawing context
CGContextRef context = UIGraphicsGetCurrentContext();
//Set the line color and width
CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:229.0/255.0 green:244.0/255.0 blue:255.0/255.0 alpha:1].CGColor);
CGContextSetLineWidth(context, 1.0f);
//Start a new Path
CGContextBeginPath(context);
//Find the number of lines in our textView + add a bit more height to draw lines in the empty part of the view
NSUInteger numberOfLines = (self.contentSize.height + rect.size.height) / self.font.lineHeight;
CGFloat baselineOffset = 6.0f;
//iterate over numberOfLines and draw each line
for (int x = 0; x < numberOfLines; x++) {
//0.5f offset lines up line with pixel boundary
CGContextMoveToPoint(context, rect.origin.x, self.font.lineHeight*x + 0.5f + baselineOffset);
CGContextAddLineToPoint(context, rect.size.width, self.font.lineHeight*x + 0.5f + baselineOffset);
}
// Close our Path and Stroke (draw) it
CGContextClosePath(context);
CGContextStrokePath(context);
}
发布于 2013-09-03 14:43:42
为什么不给文本视图一个contentInset
(和一个匹配的scrollIndicatorInsets
),而不是调整框架的大小呢?请记住,文本视图实际上是滚动视图。这是处理键盘(或其他)干扰的正确方法。
有关contentInset
的更多信息,请参阅this问题。
这似乎还不够。仍然使用插入,因为这更正确(特别是在iOS7上,键盘是透明的),但您还需要额外处理插入符号:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.textView setDelegate:self];
self.textView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_keyboardWillShowNotification:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_keyboardWillHideNotification:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)_keyboardWillShowNotification:(NSNotification*)notification
{
UIEdgeInsets insets = self.textView.contentInset;
insets.bottom += [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
self.textView.contentInset = insets;
insets = self.textView.scrollIndicatorInsets;
insets.bottom += [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
self.textView.scrollIndicatorInsets = insets;
}
- (void)_keyboardWillHideNotification:(NSNotification*)notification
{
UIEdgeInsets insets = self.textView.contentInset;
insets.bottom -= [notification.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue].size.height;
self.textView.contentInset = insets;
insets = self.textView.scrollIndicatorInsets;
insets.bottom -= [notification.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue].size.height;
self.textView.scrollIndicatorInsets = insets;
}
- (void)textViewDidBeginEditing:(UITextView *)textView
{
_oldRect = [self.textView caretRectForPosition:self.textView.selectedTextRange.end];
_caretVisibilityTimer = [NSTimer scheduledTimerWithTimeInterval:0.3 target:self selector:@selector(_scrollCaretToVisible) userInfo:nil repeats:YES];
}
- (void)textViewDidEndEditing:(UITextView *)textView
{
[_caretVisibilityTimer invalidate];
_caretVisibilityTimer = nil;
}
- (void)_scrollCaretToVisible
{
//This is where the cursor is at.
CGRect caretRect = [self.textView caretRectForPosition:self.textView.selectedTextRange.end];
if(CGRectEqualToRect(caretRect, _oldRect))
return;
_oldRect = caretRect;
//This is the visible rect of the textview.
CGRect visibleRect = self.textView.bounds;
visibleRect.size.height -= (self.textView.contentInset.top + self.textView.contentInset.bottom);
visibleRect.origin.y = self.textView.contentOffset.y;
//We will scroll only if the caret falls outside of the visible rect.
if(!CGRectContainsRect(visibleRect, caretRect))
{
CGPoint newOffset = self.textView.contentOffset;
newOffset.y = MAX((caretRect.origin.y + caretRect.size.height) - visibleRect.size.height + 5, 0);
[self.textView setContentOffset:newOffset animated:YES];
}
}
-(void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
做了很多工作,Apple应该提供更好的方法来处理插入符号,但这是有效的。
发布于 2013-10-06 00:30:22
我尝试的其他所有答案对我来说都有些奇怪。使用NSTimer
执行滚动也意味着用户不能向上滚动,因为插入符号将在屏幕外结束,并立即再次向下滚动。最后,我坚持原来的方法,即在键盘通知事件上更改UITextView
框架,然后添加以下方法:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
// Whenever the user enters text, see if we need to scroll to keep the caret on screen
[self scrollCaretToVisible];
return YES;
}
- (void)scrollCaretToVisible
{
//This is where the cursor is at.
CGRect caretRect = [self.textView caretRectForPosition:self.textView.selectedTextRange.end];
// Convert into the correct coordinate system
caretRect = [self.view convertRect:caretRect fromView:self.textView];
if(CGRectEqualToRect(caretRect, _oldRect)) {
// No change
return;
}
_oldRect = caretRect;
//This is the visible rect of the textview.
CGRect visibleRect = self.textView.frame;
//We will scroll only if the caret falls outside of the visible rect.
if (!CGRectContainsRect(visibleRect, caretRect))
{
// Work out how much the scroll position would have to change by to make the cursor visible
CGFloat diff = (caretRect.origin.y + caretRect.size.height) - (visibleRect.origin.y + visibleRect.size.height);
// If diff < 0 then this isn't to do with the iOS7 bug, so ignore
if (diff > 0) {
// Scroll just enough to bring the cursor back into view
CGPoint newOffset = self.textView.contentOffset;
newOffset.y += diff;
[self.textView setContentOffset:newOffset animated:YES];
}
}
}
对我来说就像是一种魅力
发布于 2014-04-15 14:11:07
已经有很多答案了,我发现在我的例子中实际上要简单得多。在keyboardWillShow上,我调整了文本视图的contentInset
并保持框架全屏显示。虽然scrollRangeToVisible:
对我来说并不像对其他许多人那样适用,但滚动视图方法( UITextView继承自滚动视图方法)可以很好地工作。这对我来说很有效:
- (void)textViewDidChange:(UITextView *)textView
{
CGRect caret = [_textView caretRectForPosition:_textView.selectedTextRange.end];
[_textView scrollRectToVisible:caret animated:YES];
}
https://stackoverflow.com/questions/18431684
复制相似问题