「アニメーションをNOに設定すると、すべてが期待どおりに機能する」という部分を含む、同様の問題が発生しました。
iOS 6 では、UITextView が最も近い親 UIScrollView を自動スクロールして、ファーストレスポンダーになったときにカーソルを表示することが判明しました。iOS 7 では、そのような動作はありません。UIScrollView は、ほぼ同時に scrollRectToVisible への 2 つの呼び出しによって混乱しているようです。
iOS 6 では、ほとんどの場合、 scrollRectToVisible への明示的な呼び出しは無視されます。iOS 7 のようにすべてではなく、UITextView の最初の行を表示するためだけにスクロールします (自動スクロール)。
テストするには、Xcode 5 で新しいシングル ビュー アプリを作成し、そのデプロイ ターゲットを 6.0 に設定して、ViewController.m に以下のコードを使用します。iOS 6.1 シミュレーターで実行し、スクロールして UITextView を非表示にし、画面の任意の場所をタップします。数回再試行する必要があるかもしれませんが、ほとんどの場合、最初の行だけが表示されます。WORKAROUD定義を再度有効にすると、UITextViewが独自のUIScrollViewに埋め込まれ、scrollRectToVisibleの呼び出しが期待どおりに機能します。
#import "ViewController.h"
//#define WORKAROUND
@interface ViewController ()
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UITextView *textView;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(viewTap)]];
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 240)];
self.scrollView.contentSize = CGSizeMake(320, 400);
self.scrollView.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:self.scrollView];
#ifdef WORKAROUND
UIScrollView* dummyScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(20, 280, 280, 100)];
self.textView = [[UITextView alloc] initWithFrame:dummyScrollView.bounds];
[dummyScrollView addSubview:self.textView];
[self.scrollView addSubview:dummyScrollView];
#else
self.textView = [[UITextView alloc] initWithFrame:CGRectMake(20, 280, 280, 100)];
[self.scrollView addSubview:self.textView];
#endif
self.textView.backgroundColor = [UIColor grayColor];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)viewTap
{
if (self.textView.isFirstResponder) {
[self.textView resignFirstResponder];
}
else {
[self.textView becomeFirstResponder];
}
}
- (void)keyboardWasShown:(NSNotification*)aNotification
{
#ifdef WORKAROUND
[self.scrollView scrollRectToVisible:CGRectInset(self.textView.superview.frame, 0, -10) animated:YES];
#else
[self.scrollView scrollRectToVisible:CGRectInset(self.textView.frame, 0, -10) animated:YES];
#endif
}
@end