iOS7中的UITextView非常奇怪。当您键入并输入UITextView的最后一行时,滚动视图不会像应该的那样滚动到底部,这会导致文本被“剪切”。我已经尝试将它的clipsToBound属性设置为NO但它仍然剪辑文本。
我不想调用“setContentOffset:animated”,因为对于一个:这是非常hacky的解决方案..其次:如果光标在我们的textview的中间(垂直),它将导致不必要的滚动。 / p>
这是截图。
非常感谢任何帮助!
谢谢!
答案 0 :(得分:93)
问题是由于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];
}];
}
}
答案 1 :(得分:21)
我发现here的解决方案是在创建UITextView后添加一行修复:
self.textview.layoutManager.allowsNonContiguousLayout = NO;
这一行固定three issues我创建了一个基于UITextView的代码编辑器,在iOS7上使用语法高亮显示:
注意,当键盘显示/隐藏时,我确实调整了整个UITextView的大小。
答案 2 :(得分:6)
尝试从UITextViewDelegate实现-textViewDidChangeSelection:
委托方法,如下所示:
-(void)textViewDidChangeSelection:(UITextView *)textView {
[textView scrollRangeToVisible:textView.selectedRange];
}
答案 3 :(得分:2)
这是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将无法动画到正在插入的文字。
答案 4 :(得分:1)
Imho这是iOS 7中所有典型的UITextView滚动/键盘相关问题的明确答案。它干净,易于阅读,易于使用,易于维护且可轻松完成被重用。
基本诀窍: 只需更改UITextView的大小,而不是内容插入!
这是一个动手实例。理所当然地认为你有一个使用Autolayout的基于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];
}
答案 5 :(得分:0)
textView.contentInset = UIEdgeInsetsMake(0.0, 0.0, 10.0, 0.0);
这也将解决您的问题
答案 6 :(得分:0)
如果您正在使用StoryBoard,那么如果您打开AutoLayout(默认情况下)并且没有为UITextView设置顶部/底部约束,也会发生此行为。检查文件检查器以查看您的AutoLayout状态是什么......
答案 7 :(得分:0)
这是davididsk最佳解决方案的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;
});
}
};
答案 8 :(得分:0)
此行导致最后一行文字不显示给我:
textView.scrollEnabled = false
尝试删除它,看看会发生什么......
答案 9 :(得分:-1)
textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
这解决了我的问题
答案 10 :(得分:-2)
在.m中将ViewDelegate设置为“self”并在.h中使用,然后将此代码添加到.m
将同时处理这个故障的版本,这些故障是为了进入带有文本的下一行(换行或回车)并输入...并且只返回一个回车而没有输入的下一行(此代码,与其他代码不同,将滚动显示闪烁的光标未在第二个毛刺场景中被剪辑)
//!!!*!!****!*!**!*!*!!!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;
}