本文介绍了当改变帧时,UITextView光标在帧之下的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含 UITextView UIViewCOntroller 。当键盘出现时,我按如下调整大小:

  #pragma mark  - 响应键盘事件

- (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框架。如下图所示:



/ p>

黄色区域是 UITextView 框架(我不知道R键旁边的蓝线)。我觉得这很有线。我使用iOS7如果这有什么区别。



有任何想法或建议吗?



更新 b

我有一个UITextView子类,用下面的方法绘制水平线(如果这有什么区别):

   - (void)drawRect:(CGRect)rect {

//获取当前绘图上下文
CGContextRef context = UIGraphicsGetCurrentContext
//设置线颜色和宽度
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);
//开始一个新路径
CGContextBeginPath(context);

//查找textView中的行数+添加一些高度在视图的空白部分绘制线条
NSUInteger numberOfLines =(self.contentSize.height + rect。 size.height)/ self.font.lineHeight;

CGFloat baselineOffset = 6.0f;

//遍历numberOfLines并绘制每一行
for(int x = 0; x< numberOfLines; x ++){
//0.5f 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);
}

//关闭我们的Path和Stroke(draw)it
CGContextClosePath(context);
CGContextStrokePath(context);
}


解决方案

为什么不给你的文本视图一个 contentInset (和匹配 scrollIndicatorInsets )?记住,文本视图实际上是scrollviews。这是处理键盘(或其他)干扰的正确方法。



有关 contentInset 的详细信息, a href =http://stackoverflow.com/questions/1983463/whats-the-uiscrollview-contentinset-property-for>此问题。






这似乎还不够。仍然使用插入,因为这是更正确的(特别是在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
{
//这是光标所在的位置。
CGRect caretRect = [self.textView caretRectForPosition:self.textView.selectedTextRange.end];

if(CGRectEqualToRect(caretRect,_oldRect))
return;

_oldRect = caretRect;

//这是textview的可见矩形。
CGRect visibleRect = self.textView.bounds;
visibleRect.size.height - =(self.textView.contentInset.top + self.textView.contentInset.bottom);
visibleRect.origin.y = self.textView.contentOffset.y;

//只有当光标落在可见矩形之外时,我们才会滚动。
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];
}

很多工作,苹果应该提供更好的处理插入符这工作。


I have a UIViewCOntrollerthat contains a UITextView. When the keyboard appears I resize it like this:

#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;
}

The textView seems to rezise to the right size, but when the user types the cursor ends up "outside" the textView frame. See picture below:

The yellow area is the UITextView frame (I don't know what the blue line next to the R key is). I find this quite wired. I'm using iOS7 if that makes any difference.

Any ideas or tips?

Update

I have a UITextView subclass that draws horizontal lines with the following method (if that makes any difference):

- (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);
}
解决方案

Instead of resizing the frame, why not give your text view a contentInset (and a matching scrollIndicatorInsets)? Remember that text views are actually scrollviews. This is the correct way to handle keyboard (or other) interference.

For more information on contentInset, see this question.


This seems to not be enough. Still use insets, as this is more correct (especially on iOS7, where the keyboard is transparent), but you will also need extra handling for the caret:

- (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];
}

A lot of work, Apple should provide better way of handling the caret, but this works.

这篇关于当改变帧时,UITextView光标在帧之下的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 09:59