UITableViewCell
内でカスタムUITableView
sを使用しています。これらのUITableViewCell
sはそれぞれ非常に高く、上部にUITextField
が含まれています。
ユーザーがUITextField
を編集するためにタップすると、キーボードが表示され、UITableView
が自動的にスクロールして、セルが画面の上部に表示されます。
問題は、これによりUITableView
が上部ではなくUITableViewCell
の下部にスクロールされることです。 UITableViewCell
が高く編集されている場合、UITextField
が一番上にあるため、UITextField
が見えません。 UITableView
をプログラムでスクロールする方法は知っていますが、UITableView
を自分でスクロールできるように、この自動スクロールを無効にする方法がわかりません。これどうやってするの?
Autoscroll-behaviorはUITableViewController
機能にあります。
自動スクロールを無効にするには、2つの方法を見つけました。
UITableViewController
の代わりに単にUIViewController
を使用します-データソースを設定し、自分で委任します。viewWillAppear
メソッドをオーバーライドし、[super viewWillAppear: animated]
を呼び出さないどちらのソリューションでも、Autoscrollだけでなく、Appleのクラスリファレンスの概要で説明されているその他のNiceではあるが必須ではない機能も無効にします。
https://developer.Apple.com/documentation/uikit/uitableviewcontroller
UITableViewController
のプロパティを定義します。
@property (nonatomic) BOOL scrollDisabled;
@property (nonatomic) CGFloat lastContentOffsetY;
becomeFirstResponder
を呼び出す前に:
// Save the table view's y content offset
lastContentOffsetY = tableViewController.tableView.contentOffset.y;
// Enable scrollDisabled
scrollDisabled = YES;
Table View Controllerに次のコードを追加します。
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (self.scrollDisabled) {
[self.tableView setContentOffset:CGPointMake(0, lastContentOffsetY)];
}
...
}
resignFirstResponder
を呼び出した後、scrollDisabled = NO
。
次のことができます。
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification object:nil];
}
- (void)unregisterForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidShowNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification
{
self.tableView.scrollEnabled = NO;
}
- (void)keyboardDidShow:(NSNotification *)notification
{
double delayInSeconds = 0.3;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
self.tableView.scrollEnabled = YES;
});
}
次に、このUIScrollViewDelegateメソッドを実装します
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (! self.tableView.scrollEnabled)
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
}
!!!ただし、ユーザーがキーボードで覆われるUITextFieldの場所をタップしてもスクロールしないことに注意してください。
私の観点からすると、最善のことは、キーボードが表示されるときに、上からUITextFieldが含まれるセルまでのすべてのセルが表示されるようにすることです。
私にとっての問題は、スクロールするほどではなく、編集中のテキストビューが画面から外れることでした。
したがって、スクロールを防止する代わりに、次のように、編集がトリガーされたときに目的の場所にTableViewを再スクロールするだけです:
public func textViewShouldBeginEditing(textView: UITextView) -> Bool {
dispatch_async(dispatch_get_main_queue()) {
tableViewController.tableView.scrollToRowAtIndexPath(self.indexPath!, atScrollPosition: UITableViewScrollPosition.Middle, animated: true)
}
return true
}
残念ながら、-viewWillAppear:のオーバーライドはiOS 8では機能しません。
ここに私のソリューションがあります(UITableViewController実装のように):
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] removeObserver:self.tableView name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self.tableView name:UIKeyboardWillHideNotification object:nil];
}
自動スクロール動作はUIKeyboardの表示/非表示通知によって呼び出されるため、それらを監視しないでください。
最良の方法は、UITableView
をサブクラス化してからsetContentOffset(_ contentOffset: CGPoint, animated: Bool)
をオーバーライドし、super.setContentOffset(_ contentOffset: CGPoint, animated: Bool)
を呼び出さないことです。この方法では、View Controllerが自動スクロールを実行します。
override func setContentOffset(_ contentOffset: CGPoint, animated: Bool)
{
//Do nothing
}