IOS7のUITextViewは本当に奇妙です。入力してUITextViewの最後の行を入力しているとき、スクロールビューは本来のように下部までスクロールせず、テキストが「クリッピング」されます。私は、そのclipsToBoundプロパティをNOに設定しようとしましたが、それでもテキストをクリップします。
「setContentOffset:animated」を呼び出したくないのは、その1つは非常にハッキングの解決策だからです。2つめは、カーソルがテキストビューの中央(垂直)にあると、不要なスクロールが発生するためです。
これがスクリーンショットです。
どんな助けも大歓迎です!
ありがとう!
この問題は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];
}];
}
}
私が見つけた解決策 here は、UITextViewを作成した後に1行の修正を追加することでした。
self.textview.layoutManager.allowsNonContiguousLayout = NO;
この1行は修正されました つの問題 iOS7で構文を強調表示するUITextViewベースのコードエディターを作成していました。
キーボードが表示/非表示になったときに、UITextView全体のサイズを変更したことに注意してください。
-textViewDidChangeSelection:
UITextViewDelegateのデリゲートメソッドは次のようになります。
-(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が挿入されたテキストにアニメーション化しないというバグが発生していました。
これは、iOS 7のすべての典型的なUITextViewスクロール/キーボード関連の問題に対する決定的な回答です。そのクリーンで読みやすく、読みやすい使いやすく、メンテナンスが簡単で、簡単に再利用できます。
基本的なトリック:コンテンツのインセットではなく、UITextViewのサイズを変更するだけです!
これが実践的な例です。 Autolayoutを使用してNIB /ストーリーボードベースのUIViewControllerがあり、UITextViewがUIViewControllerのルートビュー全体を埋めていることは当然です。そうでない場合は、textViewBottomSpaceConstraintを必要に応じて変更する方法を調整する必要があります。
方法:
次のプロパティを追加します。
@property (nonatomic, weak) IBOutlet NSLayoutConstraint *textViewBottomSpaceConstraint;
@property (nonatomic) CGFloat textViewBottomSpaceConstraintFromNIB;
Interface BuilderでtextViewBottomSpaceConstraintを接続します(dont forget!)
次に、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];
}
StoryBoardを使用している場合、AutoLayoutを(デフォルト)のままにし、UITextViewに上下の制約を設定しなかった場合にも、この動作が発生する可能性があります。ファイルインスペクターをチェックして、AutoLayoutの状態を確認してください...
以下は、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;
});
}
};
この行により、テキストの最後の行が表示されません。
textView.scrollEnabled = false
これを削除して、何が起こるか見てください...
textView.contentInset = UIEdgeInsetsMake(0.0, 0.0, 10.0, 0.0);
これはあなたの問題にも対処します