UITextView在iOS7剪辑文本string的最后一行

UITextView在iOS7中真的很奇怪。 当你键入并进入你的UITextView的最后一行时,滚动视图不会滚动到底部,它会导致文本被“剪辑”。 我试过把它的clipsToBound属性设置为NO,但它仍然剪辑文本。

我不想调用“setContentOffset:animated”,因为一个:这是非常hacky解决scheme..其次:如果光标在我们的textview中间(垂直),它会导致不必要的滚动。

这是一个截图。

在这里输入图像说明

任何帮助将不胜感激!

谢谢!

问题是由于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]; }]; } } 

我在这里find的解决scheme是在创buildUITextView之后添加一行修补程序:

 self.textview.layoutManager.allowsNonContiguousLayout = NO; 

这一行解决了三个问题,我在iOS7上创build了一个基于UITextView的代码编辑器,并使用语法突出显示:

  1. 滚动以便在编辑时保留文本(本post的问题)
  2. UITextView在解散键盘后偶尔会跳来跳去
  3. 尝试滚动视图时,UITextView随机滚动跳转

请注意,当键盘显示/隐藏时,我调整了整个UITextView的大小。

尝试从UITextViewDelegate实现-textViewDidChangeSelection: delegate方法,如下所示:

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

下面是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将不animation插入的文本。

Imho这是iOS 7中所有典型的UITextView滚动/键盘相关问题的明确答案 。它清晰易读,易于使用,易于维护,易于重复使用。

基本的技巧: 只需更改UITextView的大小,而不是内容插入!

这是一个动手的例子。 理所当然的是,你有一个使用Autolay的基于NIB / Storyboard的UIViewController,并且UITextView填充了UIViewController中的整个根视图。 如果没有,你将不得不调整你如何改变textViewBottomSpaceConstraint到你的需要。

如何:


添加这些属性:

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

在Interface Builder中连接textViewBottomSpaceConstraint( 别忘了!

然后在viewDidLoad中:

 // Save the state of the UITextView's 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 – 这些方法是由brennan!):

 - (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]; } 
 textView.contentInset = UIEdgeInsetsMake(0.0, 0.0, 10.0, 0.0); 

这也将解决您的问题

如果你正在使用StoryBoard,那么如果你离开了AutoLayout(因为它是默认的),并且没有为你的UITextView设置顶部/底部约束,也会发生这种行为。 检查文件检查器,看看你的AutoLayout状态是…

这是davididsk最优秀的解决scheme(从上面)的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; }); } }; 

此行导致文本的最后一行不显示为我:

 textView.scrollEnabled = false 

尝试删除这个,看看会发生什么…

  textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 

这为我解决了这个问题

在.m中设置ViewDelegate为“self”,然后在你的.h中使用,然后将这个代码添加到你的.m文件中

将同时处理这个故障的版本,正在出现的文本(包装或回车)到下一行,并input…和下​​一行只有一个回车和没有打字(这个代码,不像其他的代码,将滚动显示闪烁的光标不会在此第二个小故障情况下被剪切)

 //!!!*!!****!*!**!*!*!!!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; }