2014-01-19 2 views
5

私はiOS 7用に自分のアプリを書き直しました。新しいTextKit APIを使用しています。私はほぼ完了していますが、移行を開始して以来私が頭痛を引き起こしているもう一つの問題があります。UITextViewがテキストの削除/挿入後にスクロールアップ

問題: UITextViewにテキストを入力すると、時々表示がスクロールしてカーソルが隠れてしまいます。パターンをピンポイントするのは難しいですが、行を削除した後に表示され、下のテキストが上に移動する必要があります。

:しかし、唯一の二度目は私がとONLY(のみ改行文字を持っていますが、常にではない...一般回線)

私はstackoverflowの上でこれらのソリューションを使用してみましたが、文書内の特定の行と行を削除しますHow to stop UITextView from scrolling up when entering it

UITextView keep scrolling after every new line is inserted, so the lines are invisible (iPhone OS)

Scroll to bottom of UITextView erratic in iOS 7

のUITableViewワットを持ったときにスクロールが正しく動作しません。他の多くの問題もあります。 UITextView内にあります。私は私の見解ではテーブルビューを持っていません。

私はUITextViewをサブクラス化し、それが間違いなくiOS 7でビューを上にスクロールするだけでなく呼び出しを行うことを発見したことを指摘したいと思います。また、見知らぬ人は、(UITextViewから文字を削除するために)戻るボタンを押すと、textViewDidChangeSelection:に2つのメッセージを送信するということです。問題が発生したときのコールスタックを次に示します。 (問題が発生していないとき、私はまだ正常であると思われる... 2つのコールがtextViewDidChangeSelection:を委任してもらう):

  • UITextViewデリゲートtextViewDidChangeSelection:は、1の長さで、削除する文字の位置が含まれています。 (すなわち1050,1)
  • UITextViewデリゲートtextViewDidChangeSelection:が再度呼び出され、同じ位置に長さゼロが含まれます。 (すなわち、1050,0)
  • scrollViewDidScroll(最大3倍である。一般的に、一度だけ)
  • その後のiOS 7は、{1050,1}の最初の呼び出しの範囲のw/UITextView.scrollRangeToVisible:を呼び出します。これは私には意味がありません。この内部APIはスクロールイベントを呼び出すために使用した可能性のある関数へのトレースバックなしで_ensureselectionvisibleと呼ばれているため、これは内部的に呼び出されたものであり、私のコードからではありません。

おそらく、最初の2回の呼び出しは文字を選択するだけで、内部的にはdeleteBackwardsを呼び出します。それは理にかなっている。私はそれの後で盲目を飛んでいる。私はそれがスクロールする理由、またはWRONGの範囲を持つscrollRangeToVisible:をなぜ呼び出すのか分かりません。

ユーザーがテキストを編集しているときに[super scrollRangeToVisible]を呼び出すことなく、UITextView.scrollRangeToVisible:を乗り越えて問題を緩和することができました。私は、スクロールビューの代理コールの一部をオーバーライドし、スクロールが発生しないことを示すフラグを設定することでこれを行います。これは私にとって、巨大なUGLYハックであり、最初の編集時にビューをタップしたり、スクロールビューが減速を停止したりするなどの特定の状況でも問題が発生します。

要するに、スクロールするイベントが発生している可能性があります(おそらく、前の行が上がっているためです)、何らかの理由でiOSがカーソルが表示されていないと考えています。さらに興味深いのは、間違った範囲が指定されていても、正しい位置を提供し、ビュー内の間違った位置にスクロールするということです。さらに興味深いのは、特定の条件でのみ発生し、条件が発生する2番目のインスタンスでのみ発生するということです。私が考えることができる唯一のことは、テキストが削除された後にUITextViewの高さが正しく計算されず、テキストが実際とは異なる場所にあると考えていることです。

ありがとうございます!

UPDATE:

私はscrollViewDidScroll:で先の話を聞いたフラグを設定し、それはいくつかの他のインスタンスにジャンプを防ぐことはできません。しかし、テキストを逆方向に削除すると、まだ画面がジャンプする例があります。ビューがまだジャンプしているインスタンスでさらに奇妙なのは、[super scrollRangeToVisible]が呼び出されないようにしていることです。内部で何か起こっていることがADDITIONで表示され、ビューがスクロールします。

UPDATE:

上向き613ptsと670pts間をジャンプするように見えます。私は何がポイントの違いを引き起こすのか分からない。ジャンプする行の数も変わります。私は、何かが条件の間で似ていると思われるでしょう。また、scrollViewDidScroll:が呼び出されると、この呼び出しとデリゲートtextViewDidChangeSelection:コールの間でtextView.selectedRange.locationが同じであることが確認されました。

答えて

9

これは最近のバージョンのiOSのバグです。うまくいけば、それは私の知る限り唯一のオプションは、手動でいつでも選択が変更カーソル位置までスクロールするUITextViewを伝えることです知っているように、それまで、すぐに修正されます。

// in the text view's delegate 
- (void)textViewDidChangeSelection:(UITextView *)textView 
{ 
    [textView scrollRangeToVisible:textView.selectedRange]; 
} 

私のために動作しますが、多分バグがあることあなたのアプリには若干異なります。あなたが何をすべきかわからない...もしあなたがそれをうまくできないなら、私はAppleにTSIを提出するだろう。あなたは両方のUITextViewDelegateUIScrollViewDelegateを見ている場合scrollRangeToVisible:以来https://developer.apple.com/support/technical/submit/

+0

残念ながら、それは私の問題を解決しません。しかし、応答に感謝! – PeqNP

+0

私は間違っていた!それは私の問題を解決しました。私はまだ特定の条件でスクロールが発生しないようにするロジックを持っていました。どうもありがとうございます! – PeqNP

+0

も私の問題を解決しました – TonyTony

0

は、scrollViewDidScroll:トリガ、それはいくつかの行動の奇妙が発生します。 setContentOffset:も同じことをします。これを防ぐには、scrollView.boundsを設定する必要があります。代わりにtextViewDidChangeSelection:ではなくtextViewDidBeginEditing:を使用しました。

- (void)textViewDidBeginEditing:(UITextView *)textView { 
    CGRect caret = [textView caretRectForPosition:textView.selectedTextRange.start]; 
    UIEdgeInsets textInsets = textView.textContainerInset; 
    CGFloat textViewHeight = textView.frame.size.height - textInsets.top - textInsets.bottom; 
    // only reposition the scroll view if the caret position is out of view 
    if (textViewHeight < caret.origin.y) { 
     CGSize textSize = [textView.layoutManager usedRectForTextContainer:textView.textContainer].size; 
     // initially place the view such that the last part of the text is visible 
     CGFloat offsetY = textSize.height - textViewHeight; 
     // test to see if the caret is in the middle of the text somewhere 
     if ((caret.origin.y + (textViewHeight/2)) <= textSize.height) { 
      // we can, so center the caret in the middle of the view 
      offsetY = caret.origin.y - (textViewHeight/2); 
     } 
     // the offset indicates the point in the scrollView that will correspond to the top left of the scrollView box 
     // therefore, we need to subtract the text view height to place the caret at the bottom of the scrollView, rather than the top and some empty whitespace 
     [self repositionScrollView:textView newOffset:CGPointMake(caret.origin.x, offsetY)]; 
    } 
} 

/** 
This method allows for changing of the content offset for a UIScrollView without triggering the scrollViewDidScroll: delegate method. 
*/ 
- (void)repositionScrollView:(UIScrollView *)scrollView newOffset:(CGPoint)offset { 
    CGRect scrollBounds = scrollView.bounds; 
    scrollBounds.origin = offset; 
    scrollView.bounds = scrollBounds; 
} 

contentOffsettextSize.height - textViewHeightより大きくなることはありませんので、一番下の空白がありません。テキストが多少長い場合、コードはUITextViewの中央にキャレットを配置します。これは、キャレットの上と下の両方のテキストのコンテキストをユーザに与えるため、これが最良の動作です。

関連する問題