当键盘可见时,如何让UITextView正确滚动

Nei*_*ard 15 iphone

我有一个UITextView坐在UIView的顶部,如果我点击它打开它进行编辑,那么键盘阻挡了视图的底部,即使我可以在这个区域写,我也看不到它.我可以告诉UITextView有不同的滚动区域或解决方案是什么?

小智 31

一个更好的解决方案,特别是针对iOS 7,将调整textview的内容插入属性而不是其框架,这样,键盘将模糊落后的文本,就像在任何其他iOS 7应用程序中一样.您还必须调整滚动指示符以匹配.

扩大林德曼的答案,

- (void)keyboardWasShown:(NSNotification*)notification {
    NSDictionary* info = [notification userInfo];
    CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;

    self.textView.contentInset = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0);
    self.textView.scrollIndicatorInsets = self.textView.contentInset;
}

- (void)keyboardWillBeHidden:(NSNotification*)notification {
    self.textView.contentInset = UIEdgeInsetsZero;
    self.textView.scrollIndicatorInsets = UIEdgeInsetsZero;
}
Run Code Online (Sandbox Code Playgroud)


Lin*_*ann 14

一个简单的解决方案是实现UITextViewDelegate方法

- (void)textViewDidBeginEditing:(UITextView *)textView
Run Code Online (Sandbox Code Playgroud)

- (void)textViewDidEndEditing:(UITextView *)textView
Run Code Online (Sandbox Code Playgroud)

您可以在键盘出现时使UITextView框架更小,并在键盘消失时再次将其设置为全尺寸...如下所示:

- (void)textViewDidBeginEditing:(UITextView *)textView {
    self.textView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height/1.8);
}

- (void)textViewDidEndEditing:(UITextView *)textView {
    self.textView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
}
Run Code Online (Sandbox Code Playgroud)

编辑

上面的解决方案很糟糕......不要使用它!

现在,我认为这是一个更好的主意来调整的UITextView按比例键盘大小,而不是一个固定值...因为当其他语言成为选择或成为设备的旋转...当然键盘的大小可以改变-.-

首先,您必须注册您的UIViewController显示您UITextView的接收键盘通知:

- (void)viewDidLoad {
    [super viewDidLoad];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(keyboardWasShown:)
                                                     name:UIKeyboardDidShowNotification object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(keyboardWillBeHidden:)
                                                     name:UIKeyboardWillHideNotification object:nil]; 
}
Run Code Online (Sandbox Code Playgroud)

然后你必须实现这两个方法-keyboardWasShown:-keyboardWillBeHidden:.

实际键盘的大小包含在NSNotification对象中.

- (void)keyboardWasShown:(NSNotification*)notification {
    NSDictionary* info = [notification userInfo];
    CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
    self.textView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - keyboardSize.height);
}

- (void)keyboardWillBeHidden:(NSNotification*)notification {
    self.textView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
}
Run Code Online (Sandbox Code Playgroud)


Joh*_*kex 5

如果您想要一个消息应用程序样式输入,您可以使用嵌套的UITextView(允许多行文本).它最终看起来像这样:

在此输入图像描述

首先,布置一个视图来保存所有子视图.这里bottomView的背景颜色设置为与UIKeyboardAppearanceDark匹配.它位于屏幕的底部.

bottomView = [UIView new];
bottomView.frame = CGRectMake(0, h-45, w, 45);
bottomView.backgroundColor = [UIColor colorWithRed:0.078 green:0.078 blue:0.078 alpha:1];
[self.view addSubview:bottomView];
Run Code Online (Sandbox Code Playgroud)

然后,添加一个简单的背景视图,其样式与典型的UITextField类似,并将UITextView作为子视图添加到其中.inputTV(UITextView)根据字体大小获取其高度.此外,使用textContainer变量从inputTV中删除所有填充.

inputTVBG = [UIImageView new];
inputTVBG.frame = CGRectMake(10, 8, w-90, 29);
inputTVBG.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.1f];
inputTVBG.layer.cornerRadius = 4.0f;
inputTVBG.userInteractionEnabled = true;
inputTVBG.clipsToBounds = true;
[bottomView addSubview:inputTVBG];

inputTV = [UITextView new];
inputTV.font = [UIFont systemFontOfSize:14.0f];
inputTV.frame = CGRectMake(5, 6, w-100, inputTV.font.lineHeight);
inputTV.backgroundColor = [UIColor clearColor];
inputTV.keyboardAppearance = UIKeyboardAppearanceDark;
inputTV.delegate = self;
inputTV.autocorrectionType = UITextAutocorrectionTypeNo;
inputTV.tintColor = [UIColor whiteColor];
inputTV.textColor = [UIColor whiteColor];
inputTV.textContainer.lineFragmentPadding = 0;
inputTV.textContainerInset = UIEdgeInsetsZero;
[inputTVBG addSubview:inputTV];
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,我添加了一个标签,指示剩余的字母数(最大/最小字符数)和提交按钮.

lettersLeftLabel = [UILabel new];
lettersLeftLabel.frame = CGRectMake(w-70, 8, 60, 16);
lettersLeftLabel.font = [UIFont systemFontOfSize:12.0f];
lettersLeftLabel.textColor = [[UIColor whiteColor] colorWithAlphaComponent:0.5f];
lettersLeftLabel.alpha = 0.0f;
[bottomView addSubview:lettersLeftLabel];

submitButton = [UIButton new];
submitButton.frame = CGRectMake(w-70, 0, 60, 45);
[submitButton setTitle:@"SUBMIT" forState:UIControlStateNormal];
[submitButton setTitleColor:[_peacock.applePink colorWithAlphaComponent:0.5f] forState:UIControlStateNormal];
[submitButton addTarget:self action:@selector(submit) forControlEvents:UIControlEventTouchUpInside];
[submitButton.titleLabel setFont:[UIFont boldSystemFontOfSize:14.0f]];
[bottomView addSubview:submitButton];
Run Code Online (Sandbox Code Playgroud)

在代码的早期添加此行,以便获得键盘更改更新:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
Run Code Online (Sandbox Code Playgroud)

当用户点击inputTV时,它会调用以下方法.这里设置了稍后使用的变量'keyboardHeight'.

-(void)keyboardWillShow:(NSNotification *)n {
    CGRect rect = [n.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGRect keyboardFrame = [self.view convertRect:rect fromView:nil];
    keyboardHeight = keyboardFrame.size.height;
    [self textViewDidChange:inputTV];
}
Run Code Online (Sandbox Code Playgroud)

这是代码的主要部分,它负责输入电视的所有移动和调整大小.

-(void)textViewDidChange:(UITextView *)textView {

    //1. letters and submit button vars
    int numberOfCharacters = (int)textView.text.length;
    int minCharacters = 50;
    int maxCharacters = 400;
    int remainingCharacters = maxCharacters-numberOfCharacters;

    //2. if entered letters exceeds maximum, reset text and return
    if (remainingCharacters <= 0){
        textView.text = [textView.text substringToIndex:maxCharacters];
        numberOfCharacters = maxCharacters;
    }

    //3. set height vars
    inputTV.scrollEnabled = true;
    float textHeight = textView.contentSize.height;
    float lineHeight = roundf(textView.font.lineHeight);
    float additionalHeight = textHeight - lineHeight;
    float moveUpHeight = keyboardHeight + additionalHeight;

    //4. default letter colour is weak white
    UIColor * letterColour = [[UIColor whiteColor] colorWithAlphaComponent:0.5f];
    if (numberOfCharacters < minCharacters){ //minimum threshold not met
        lettersLeftLabel.text = [NSString stringWithFormat:@"%i",  minCharacters-numberOfCharacters];
        letterColour = [_peacock.applePink colorWithAlphaComponent:0.5f];
    } else { //within range
        lettersLeftLabel.text = [NSString stringWithFormat:@"%i/%i", numberOfCharacters, maxCharacters];
        if (remainingCharacters<5){ //increase alpha towards the end of range
            letterColour = [[UIColor whiteColor] colorWithAlphaComponent:1.0f - ((float)remainingCharacters/10)];
        }
    }

    //5. hide/show letter label based on textView height
    float letterAlpha = 0.0f; //default hide
    if (additionalHeight > 0){ letterAlpha = 1.0f; } //if multiline, show
    [UIView animateWithDuration:0.3f
                          delay:0.0f
                        options:UIViewAnimationOptionCurveEaseOut
                     animations:^{
                         lettersLeftLabel.alpha = letterAlpha;
                         lettersLeftLabel.textColor = letterColour;
                     }
                     completion:^(BOOL finished){
                     }];

    //6. update submit colour based on minimum threshold
    UIColor * submitColour = [_peacock.applePink colorWithAlphaComponent:0.5f];
    bool enableSubmit = false;
    if (numberOfCharacters >= minCharacters){
        submitColour = _peacock.applePink;
        enableSubmit = true;
    }
    [submitButton setEnabled:enableSubmit];
    [UIView animateWithDuration:0.3f
                          delay:0.0f
                        options:UIViewAnimationOptionCurveEaseOut
                     animations:^{
                         [submitButton setTitleColor:submitColour forState:UIControlStateNormal];
                     }
                     completion:^(BOOL finished){
                     }];



    //7. special case if you want to limit the frame size of the input TV to a specific number of lines
    bool shouldEnableScroll = false;
    int maxNumberOfLines = 5; //anything above this triggers the input TV to stay stationary and update its scroll
    int actualNumberOfLines = textHeight / textView.font.lineHeight;
    if (actualNumberOfLines >= maxNumberOfLines){ //recalculate vars for frames
        textHeight = maxNumberOfLines * lineHeight;
        additionalHeight = textHeight - lineHeight;
        moveUpHeight = keyboardHeight + additionalHeight;
        shouldEnableScroll = true;
    }

    //8. adjust frames of views
    inputTV.frame = CGRectMake(5, 6, w-100, textHeight); //update immediately (parent view clips to bounds)
    [UIView animateWithDuration:0.3f
                          delay:0.0f
                        options:UIViewAnimationOptionCurveEaseOut
                     animations:^{
                         bottomView.frame = CGRectMake(0, h-45-moveUpHeight, w, 45+additionalHeight);
                         inputTVBG.frame = CGRectMake(10, 8, w-90, lineHeight+additionalHeight+13);
                         submitButton.frame = CGRectMake(w-70, additionalHeight, 60, 45);
                     }
                     completion:^(BOOL finished){
                         inputTV.scrollEnabled = shouldEnableScroll; //default disable scroll here to avoid bouncing

                     }];


}
Run Code Online (Sandbox Code Playgroud)

在上面的方法中,这就是发生的事情:

  1. 如果要设置最小或最大字符数,可以在此处执行此操作.您拉出字符数并存储为整数,并计算剩余的字符数.

  2. 如果用户已达到最大字符数,请通过剥离回到最大值来重置textView文本.

  3. 这些变量用于计算移动底部视图所需的量,以及调整其子视图的大小.

  4. 此方法仅用于更改某些UI元素的颜色/文本.这不是绝对必要的.

  5. 如果你正在使用它,这个方法将lettersLeftLabel带到视图上.它也没有必要.

  6. 仅在达到最小字符数时才启用提交按钮.它将颜色更改为用户的指示.

  7. 如果要限制inputTV和周围元素的增长,可以包含这一部分代码.它要求您设置要显示的最大行数.如果用户超过最大值,则为inputTV重新启用滚动,否则默认为false(重要的是停止弹跳).

  8. 这是主要的调整大小逻辑,移动bottomView并调整其子视图的大小.提交按钮需要保持在相同的位置,因此随着bottomView的增长将其向下移动.

注意:如果您只想要准系统代码,则只需执行步骤3和8.


Nei*_*ard 4

我终于让它工作了。这是我的解决方案,你们能发现我的设计中有什么错误吗?

@synthesize textView = _textView;
@synthesize callbackViewController = _callbackViewController;


-(void)keyboardWasShown:(NSNotification*)aNotification {
    if(keyboardShown) {
        return;
    }

    NSDictionary *info = [aNotification userInfo];

    // Get the size of the keyboard.
    NSValue *aValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey];
    keyboardSize = [aValue CGRectValue].size;

    // Resize the scroll view (which is the root view of the window)
    CGRect viewFrame = [self.textView frame];

    orientationAtShown = orientation;

    if(orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
        viewFrame.size.height -= keyboardSize.height;
    } else {
        viewFrame.size.height -= keyboardSize.width;
    }

    self.textView.frame = viewFrame;

    // Scroll the active text field into view.
    //CGRect textFieldRect = [activeField frame];
    [self.textView scrollRectToVisible:viewFrame animated:YES];

    keyboardShown = YES;
}

-(void)keyboardWasHidden:(NSNotification*)aNotification {
    if(!keyboardShown) {
        return;
    }

    // Reset the height of the scroll view to its original value
    CGRect viewFrame = [self.textView frame];
    if(orientationAtShown == UIInterfaceOrientationPortrait || orientationAtShown == UIInterfaceOrientationPortraitUpsideDown) {
        viewFrame.size.height += keyboardSize.height;
    } else {
        viewFrame.size.height += keyboardSize.width;
    }

    self.textView.frame = viewFrame;

    keyboardShown = NO;
}

-(void)registerForKeyboardNotifications {
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWasShown:)
                                                 name:UIKeyboardDidShowNotification object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWasHidden:)
                                                 name:UIKeyboardDidHideNotification object:nil];
}

-(void)viewWillAppear:(BOOL)animated {
    keyboardShown = NO;
    [self registerForKeyboardNotifications];
}

-(void)viewWillDisappear:(BOOL)animated {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
}

// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    if(keyboardShown) {
        [self keyboardWasHidden:nil];
    }

    orientation = interfaceOrientation;

    CGRect viewFrame = [self.textView frame];
    if(orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
        if(viewFrame.size.width > viewFrame.size.height) {
            CGRect viewFrameFixed = CGRectMake(viewFrame.origin.x, viewFrame.origin.y, viewFrame.size.height, viewFrame.size.width);
            self.textView.frame = viewFrameFixed;
        }
    } else {
        if(viewFrame.size.width < viewFrame.size.height) {
            CGRect viewFrameFixed = CGRectMake(viewFrame.origin.x, viewFrame.origin.y, viewFrame.size.height, viewFrame.size.width);
            self.textView.frame = viewFrameFixed;
        }
    }


    // Return YES for supported orientations
    return YES;
}
Run Code Online (Sandbox Code Playgroud)