UITextView в iOS7 зажимает последнюю строку текстовой строки
UITextView в iOS7 был действительно странным. Когда вы вводите и вводите последнюю строку своего UITextView, прокрутка не прокручивается до нижней части, как должна, и это заставляет текст "обрезать". Я пробовал установить для свойства clipsToBound значение НЕТ, но он по-прежнему зажимает текст.
Я не хочу вызывать "setContentOffset: анимированный", потому что для одного: это очень хакерское решение.. во-вторых: если курсор находился посередине (по вертикали) нашего текстового поля, это вызовет нежелательную прокрутку.
Вот скриншот.
![enter image description here]()
Любая помощь будет принята с благодарностью!
Спасибо!
Ответы
Ответ 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;
}