2010-09-29 4 views
12

У меня есть UITextView, сидящий поверх UIView, и если я нажму на него, чтобы открыть его для редактирования, то клавиатура блокирует нижнюю часть представления и Я не вижу этого, хотя я могу писать в этой области. Могу ли я указать UITextView, чтобы иметь другую область прокрутки или какое решение?Как заставить UITextView правильно прокручивать, когда клавиатура видна?

+1

дубликат смотрите здесь для ответа http://stackoverflow.com/questions/1126726/how-to -make-a-uitextfield-move-up-when-keyboard-is-present –

ответ

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; 
}
+0

orientationAtShown ???? у вас есть списки членов данных здесь без каких-либо деклараций или объяснений. – iOSProgrammingIsFun

4

У Apple есть code samples, которые касаются этой точной ситуации.

+0

Я реализовал пример из ссылки, и он работает, но область прокрутки для моего UITextView становится довольно маленькой (например, 50 пикселей). Любая идея почему? – Neigaard

+0

Проверьте маски изменения размера в Interface Builder. Я не уверен, каковы правильные настройки, но они контролируют, как текстовое представление реагирует на изменения размера его родителя. –

+0

Когда вы говорите об изменении размера маски, то что вы имеете в виду? – Neigaard

15

Простое решение заключается в реализации UITextViewDelegate методы

- (void)textViewDidBeginEditing:(UITextView *)textView 

и

- (void)textViewDidEndEditing:(UITextView *)textView 

Вы можете сделать 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); 
} 

EDIT

Раствор выше плохо ... не использовать !!!

Теперь я думаю, что лучше изменить размер 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]; 
} 

Тогда вы должны реализовать два метода -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); 
} 
+0

это правильный ответ! –

+1

Нет, это не так. Отрегулируйте contentInsets, а не фрейм. – Linasses

29

Лучшее решением, специально для прошивки 7, будет регулировать содержание врезки свойства TextView вместо рамы, таким образом, клавиатура размывает текст, который падает задом его, как и в любой другой прошивке 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; 
} 
+0

Спасибо за этот ответ. Это должно быть абсолютно отмечено как «правильный» ответ, особенно, как вы упомянули, учитывая изменения в iOS 7. – Mani

+0

В iOS 8 это, похоже, происходит автоматически – adamF

+1

@adamF Это не происходит автоматически для меня в iOS 8 .. – Jacob

4

@Alejandro выше, имеет право идеи, но его код не работает в ландшафтном режиме.Я изменил свое keyboardWasShown: метод корректно работать во всех направлениях:

- (void)keyboardWasShown:(NSNotification *)notification { 
    if (self.textView != nil) { 
     NSDictionary* info = [notification userInfo]; 
     CGRect keyboardRect = [self.textView convertRect:[[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue] fromView:nil]; 
     CGSize keyboardSize = keyboardRect.size;   

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

Расширение @alejandro & @Mani:

Th окончательный ответ:

- (void)keyboardWasShown:(NSNotification *)notification { 
    if (self.textView != nil) { 
     NSDictionary* info = [notification userInfo]; 
     CGRect keyboardRect = [self.textNote convertRect:[[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue] fromView:nil]; 
     CGSize keyboardSize = keyboardRect.size; 

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

- (void)keyboardWillBeHidden:(NSNotification*)notification { 

    self.textView.scrollIndicatorInsets = UIEdgeInsetsZero; 
    self.textView.scrollIndicatorInsets = UIEdgeInsetsZero; 
} 
+0

Это не работает так хорошо, может быть проблема UIKeyboardFrameEndUserInfoKey? – slboat

2

Добавить Observer первым в viewDidLoad.

- (void)viewDidLoad { 
    [super viewDidLoad]; 

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

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

} 

Вызов методов

- (void)keyboardWasShown:(NSNotification*)aNotification 
{ 
NSDictionary* info = [aNotification userInfo]; 
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; 

UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0); 
self.textView.contentInset = contentInsets; 
self.textView.scrollIndicatorInsets = contentInsets; 

// If active text field is hidden by keyboard, scroll it so it's visible 
// Your app might not need or want this behavior. 
CGRect aRect = self.view.frame; 
aRect.size.height -= kbSize.height; 
if (!CGRectContainsPoint(aRect, self.textView.frame.origin)) { 
    [self.textView scrollRectToVisible:self.textView.frame animated:YES]; 
} 
} 

// Called when the UIKeyboardWillHideNotification is sent 
- (void)keyboardWasHidden:(NSNotification*)aNotification 
{ 
    UIEdgeInsets contentInsets = UIEdgeInsetsZero; 
    self.textView.contentInset = contentInsets; 
    self.textView.scrollIndicatorInsets = contentInsets; 
} 
1

если у вас есть более 1 текстовое поле или вы хотите уменьшить свой код, то попробуйте этот код

- (void)textFieldDidBeginEditing:(UITextField *)textField{ 

    [UIView beginAnimations:nil context:NULL]; 
    [UIView setAnimationDuration:0.35f]; 
    CGRect frame = self.view.frame; 
    frame.origin.y = (self.view.frame.size.height - textField.frame.origin.y) - self.view.frame.size.height+60; 
    if (frame.origin.y<-162) { 
     frame.origin.y = -162; 
    } 
    [self.view setFrame:frame]; 
    [UIView commitAnimations]; 
} 
-(BOOL)textFieldShouldEndEditing:(UITextField *)textField{ 
    [UIView beginAnimations:nil context:NULL]; 
    [UIView setAnimationDuration:0.35f]; 
    CGRect frame = self.view.frame; 
    frame.origin.y = 0; 
    [self.view setFrame:frame]; 
    [UIView commitAnimations]; 
    return YES; 

} 
3

Если вы хотите ввод сообщений App стиль , вы можете использовать вложенный UITextView (допускается несколько строк текста). Это будет выглядеть в конце:

enter image description here

Вы начинаете выложив вид держать все мнения ребенка. Здесь фоновый цвет 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]; 

Затем добавьте в простой взгляд фоне стилизованного как типичный UITextField, и добавьте UITextView как подвид к этому. Входной ТВ (UITextView) занимает высоту, основанную на размере шрифта. Кроме того, все дополнения удаляются из inputTV с использованием переменных textContainer.

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

В приведенном выше примере, я включил метку, указывающую, сколько букв остались (макс/мин символы) и кнопки отправки.

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

Добавьте эту строку в начале в вашем коде, так что вы получите обновление изменения клавиатуры:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; 

Он вызывает метод ниже, когда пользователь нажимает на 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]; 
} 

Это основной бит кода, который заботится обо всех перемещениях и изменении размера входного ТВ.

-(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 

        }]; 


} 

В описанном выше способе, это то, что происходит:

  1. Если вы хотите установить минимальное или максимальное количество символов, вы можете сделать это здесь. Вы вытягиваете количество символов и сохраняете как целое число, и вычисляете, сколько символов осталось.

  2. Если пользователь достиг максимального количества символов, сбросьте текст textView, отменив его до макс.

  3. Эти вары используются для расчета того, сколько вам нужно переместить снизу вверх, а также для изменения размеров его подзонов.

  4. Этот метод предназначен только для изменения цвета/текста некоторых элементов пользовательского интерфейса. Это не обязательно.

  5. Этот метод выводит на экран буквыLeftLabel, если вы используете это. Это тоже не обязательно.

  6. Это позволяет отправить кнопку, только если достигнуто минимальное количество символов. Он изменяет цвет в качестве индикатора для пользователя.

  7. Если вы хотите ограничить рост входного ТВ и окружающих элементов, вы можете включить этот бит кода. Для этого требуется установить максимальное количество строк, которые вы хотите отобразить. Если пользователь превышает максимальный, прокрутка повторно используется для входного ТВ, в противном случае по умолчанию используется значение false (важно остановить его подпрыгивание).

  8. Это основная логика изменения размера, перемещение снизу вверх и изменение размеров его дочерних видов. Кнопка отправки должна оставаться в том же положении, поэтому перемещайте ее вниз по мере роста bottomView.

ПРИМЕЧАНИЕ: Если вы просто хотите баребоны код, вам нужно всего лишь осуществить шаги 3 и 8.

Смежные вопросы