Подтвердить что ты не робот

UITextView в iOS7 зажимает последнюю строку текстовой строки

UITextView в iOS7 был действительно странным. Когда вы вводите и вводите последнюю строку своего UITextView, прокрутка не прокручивается до нижней части, как должна, и это заставляет текст "обрезать". Я пробовал установить для свойства clipsToBound значение НЕТ, но он по-прежнему зажимает текст.

Я не хочу вызывать "setContentOffset: анимированный", потому что для одного: это очень хакерское решение.. во-вторых: если курсор находился посередине (по вертикали) нашего текстового поля, это вызовет нежелательную прокрутку.

Вот скриншот.

enter image description here

Любая помощь будет принята с благодарностью!

Спасибо!

4b9b3361

Ответ 1

Проблема связана с iOS 7. В делегате текстового представления добавьте этот код:

- (void)textViewDidChange:(UITextView *)textView {
    CGRect line = [textView caretRectForPosition:
        textView.selectedTextRange.start];
    CGFloat overflow = line.origin.y + line.size.height
        - ( textView.contentOffset.y + textView.bounds.size.height
        - textView.contentInset.bottom - textView.contentInset.top );
    if ( overflow > 0 ) {
        // We are at the bottom of the visible text and introduced a line feed, scroll down (iOS 7 does not do it)
        // Scroll caret to visible area
        CGPoint offset = textView.contentOffset;
        offset.y += overflow + 7; // leave 7 pixels margin
        // Cannot animate with setContentOffset:animated: or caret will not appear
        [UIView animateWithDuration:.2 animations:^{
            [textView setContentOffset:offset];
        }];
    }
}

Ответ 2

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

self.textview.layoutManager.allowsNonContiguousLayout = NO;

Эта одна строка исправлена ​​три вопроса У меня было создание редактора кода на основе UITextView с подсветкой синтаксиса на iOS7:

  • Прокрутка для просмотра текста при редактировании (проблема с этим сообщением)
  • UITextView иногда прыгает после отклонения клавиатуры.
  • UITextView случайные прокрутки при попытке прокрутки представления

Примечание. Я изменил размер всего UITextView, когда клавиатура показана/скрыта.

Ответ 3

Попробуйте реализовать метод делегата -textViewDidChangeSelection: из UITextViewDelegate следующим образом:

-(void)textViewDidChangeSelection:(UITextView *)textView {
    [textView scrollRangeToVisible:textView.selectedRange];
}

Ответ 4

Имеет измененную версию выбранного ответа davidisdk.

- (void)textViewDidChange:(UITextView *)textView {
    NSRange selection = textView.selectedRange;

    if (selection.location + selection.length == [textView.text length]) {
        CGRect caretRect = [textView caretRectForPosition:textView.selectedTextRange.start];
        CGFloat overflow = caretRect.origin.y + caretRect.size.height - (textView.contentOffset.y + textView.bounds.size.height - textView.contentInset.bottom - textView.contentInset.top);

        if (overflow > 0.0f) {
            CGPoint offset = textView.contentOffset;
            offset.y += overflow + 7.0f;

            [UIView animateWithDuration:0.2f animations:^{
                [textView setContentOffset:offset];
            }];
        }
    } else {
        [textView scrollRangeToVisible:selection];
    }
}

Я получал ошибку, когда размер содержимого textView больше, чем границы и курсор - вне экрана (например, с помощью клавиатуры и нажатия клавиши со стрелкой), textView не будет анимировать добавляемый текст.

Ответ 5

Imho это окончательный ответ для всех типичных проблем, связанных с прокруткой/клавиатурой UITextView, в iOS 7. Его чистый, простой в использовании, простой в использовании, простой в обслуживании и может легко повторно использовать.

Основной трюк: Просто измените размер UITextView, а не на вставку содержимого!

Вот практический пример. Само собой разумеется, что у вас есть UIViewController на основе NIB/Storyboard, используя Autolayout, а UITextView заполняет весь корневой вид в UIViewController. Если нет, вам придется адаптироваться, как вы изменяете textViewBottomSpaceConstraint в соответствии с вашими потребностями.

Как сделать:


Добавьте эти свойства:

@property (nonatomic, weak) IBOutlet NSLayoutConstraint *textViewBottomSpaceConstraint;
@property (nonatomic) CGFloat textViewBottomSpaceConstraintFromNIB;

Подключить конструкцию textViewBottomSpaceConstraint в построителе интерфейса (не забыть!)

Затем в viewDidLoad:

// Save the state of the UITextView bottom constraint as set up in your NIB/Storyboard
self.textViewBottomSpaceConstraintFromNIB = self.textViewBottomSpaceConstraint.constant;

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

Добавьте эти методы для обработки изменения размера клавиатуры (спасибо https://github.com/brennanMKE/Interfaces/tree/master/Keyboarding - эти методы написаны brannan!):

- (void)keyboardWillShowNotification:(NSNotification *)notification {
    CGFloat height = [self getKeyboardHeight:notification forBeginning:TRUE];
    NSTimeInterval duration = [self getDuration:notification];
    UIViewAnimationOptions curve = [self getAnimationCurve:notification];

    [self keyboardWillShowWithHeight:height duration:duration curve:curve];
}

- (void)keyboardWillHideNotification:(NSNotification *)notification {
    CGFloat height = [self getKeyboardHeight:notification forBeginning:FALSE];
    NSTimeInterval duration = [self getDuration:notification];
    UIViewAnimationOptions curve = [self getAnimationCurve:notification];

    [self keyboardWillHideWithHeight:height duration:duration curve:curve];
}

- (NSTimeInterval)getDuration:(NSNotification *)notification {
    NSDictionary *info = [notification userInfo];

    NSTimeInterval duration;

    NSValue *durationValue = [info objectForKey:UIKeyboardAnimationDurationUserInfoKey];
    [durationValue getValue:&duration];

    return duration;
}

- (CGFloat)getKeyboardHeight:(NSNotification *)notification forBeginning:(BOOL)forBeginning {
    NSDictionary *info = [notification userInfo];

    CGFloat keyboardHeight;

    NSValue *boundsValue = nil;
    if (forBeginning) {
        boundsValue = [info valueForKey:UIKeyboardFrameBeginUserInfoKey];
    }
    else {
        boundsValue = [info valueForKey:UIKeyboardFrameEndUserInfoKey];
    }

    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
    if (UIDeviceOrientationIsLandscape(orientation)) {
        keyboardHeight = [boundsValue CGRectValue].size.width;
    }
    else {
        keyboardHeight = [boundsValue CGRectValue].size.height;
    }

    return keyboardHeight;
}

- (UIViewAnimationOptions)getAnimationCurve:(NSNotification *)notification {
    UIViewAnimationCurve curve = [[notification.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];

    switch (curve) {
        case UIViewAnimationCurveEaseInOut:
            return UIViewAnimationOptionCurveEaseInOut;
            break;
        case UIViewAnimationCurveEaseIn:
            return UIViewAnimationOptionCurveEaseIn;
            break;
        case UIViewAnimationCurveEaseOut:
            return UIViewAnimationOptionCurveEaseOut;
            break;
        case UIViewAnimationCurveLinear:
            return UIViewAnimationOptionCurveLinear;
            break;
    }

    return kNilOptions;
}

Наконец, добавьте эти методы для реагирования на уведомления клавиатуры и измените размер UITextView

- (void)keyboardWillShowWithHeight:(CGFloat)height duration:(CGFloat)duration curve:(UIViewAnimationOptions)curve
{
    CGFloat correctionMargin = 15; // you can experiment with this margin so the bottom text view line is not flush against the keyboard which doesn't look nice
    self.textViewBottomSpaceConstraint.constant = height + correctionMargin;

    [self.view setNeedsUpdateConstraints];

    [UIView animateWithDuration:duration delay:0 options:curve animations:^{
        [self.view layoutIfNeeded];
    } completion:^(BOOL finished) {

    }];
}

- (void)keyboardWillHideWithHeight:(CGFloat)height duration:(CGFloat)duration curve:(UIViewAnimationOptions)curve
{
    self.textViewBottomSpaceConstraint.constant = self.textViewBottomSpaceConstraintFromNIB;

    [self.view setNeedsUpdateConstraints];

    [UIView animateWithDuration:duration delay:0 options:curve animations:^{
        [self.view layoutIfNeeded];
    } completion:^(BOOL finished) {

    }];
}

Также добавьте эти методы для автоматического прокрутки туда, где пользователь нажал

- (void)textViewDidBeginEditing:(UITextView *)textView
{
    [textView scrollRangeToVisible:textView.selectedRange];
}

- (void)textViewDidChangeSelection:(UITextView *)textView
{
    [textView scrollRangeToVisible:textView.selectedRange];
}

Ответ 6

textView.contentInset = UIEdgeInsetsMake(0.0, 0.0, 10.0, 0.0);

Это также затронет вашу проблему.

Ответ 7

Если вы используете StoryBoard, это поведение также может произойти, если вы покинули AutoLayout (по умолчанию) и не установили ограничения верхнего и нижнего уровня для вашего UITextView. Проверьте инспектор файлов, чтобы узнать, что ваш статус AutoLayout...

Ответ 8

Вот версия давидидской версии MonoTouch (сверху).

TextView.SelectionChanged += (object sender, EventArgs e) => {
                TextView.ScrollRangeToVisible(TextView.SelectedRange);
            };


            TextView.Changed += (object sender, EventArgs e) => {

                CGRect line = TextView.GetCaretRectForPosition(TextView.SelectedTextRange.Start);
                nfloat overflow = line.Y + line.Height - 
                                     (TextView.ContentOffset.Y + 
                                      TextView.Bounds.Height -          
                                      TextView.ContentInset.Bottom -
                                      TextView.ContentInset.Top );
                if ( overflow > 0 ) 
                {
                    // We are at the bottom of the visible text and introduced 
                    // a line feed, scroll down (iOS 7 does not do it)
                    // Scroll caret to visible area
                    CGPoint offset = TextView.ContentOffset;
                    offset.Y+= overflow + 7; // leave 7 pixels margin
                    // Cannot animate with setContentOffset:animated: 
                    // or caret will not appear
                    UIView.Animate(0.1,()=> {
                        TextView.ContentOffset = offset;
                    });
                }
            };

Ответ 9

Эта строка приводит к тому, что последняя строка текста не отображается для меня:

textView.scrollEnabled = false

Попробуйте удалить это и посмотреть, что произойдет...

Ответ 10

   textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

Это разрешило проблему для меня

Ответ 11

Установите theViewDelegate на "self" в вашем .m и используйте в вашем .h, затем добавьте этот код в свой .m

Будут обрабатывать BOTH версии этого сбоя, которые происходят для перехода к следующей строке с текстом (обертывание или возврат каретки) и ввода... И переход к следующей строке только с возвратом каретки и без ввода (этот код, в отличие от другого кода, прокрутит, чтобы показать, что мигающий курсор не обрезается в этом втором сценарии сбой)

//!!!*!!****!*!**!*!*!!!MAKE SURE YOU SET DELEGATE AND USE THE <UITEXTVIEWDELEGATE>

-(void)textViewDidChange:(UITextView *)textView {
    [theTextView scrollRangeToVisible:[textView selectedRange]];//resizing textView frame causes text itself "content frame?" to still go below the textview frame and get clipped... auto-scrolling must be implimented. (iOS7 bug)
}

-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    if (([text isEqualToString:@"\n"]) && (range.location == textView.text.length)) {//"return" at end of textView
        [textView scrollRectToVisible:CGRectMake(5,5,5,999999999999999999) animated:NO];//for some reason the textViewDidChange auto scrolling doesnt work with a carriage return at the end of your textView... so I manually set it INSANELY low (NOT ANIMATED) here so that it automagically bounces back to the proper position before interface refreshes when textViewDidChange is called after this.
    }
    return YES;
}