テキストフィールドが選択されたときにUITableViewをスクロールさせる


251

多くの試行錯誤の後、私はあきらめて質問をしています。同様の問題を抱えている多くの人を見てきましたが、すべての答えが正しく機能するわけではありません。

私が持っているUITableViewカスタムセルで構成されています。セルは、隣り合った5つのテキストフィールドで構成されています(グリッドのようなものです)。

の下部にあるセルをスクロールして編集しようとするとUITableView、キーボードの上にセルを適切に配置することができません。

ビューサイズの変更などについて多くの回答が見られますが、これまでのところ、どれもうまく機能していません。

誰かがこれを行う「正しい」方法を具体的なコード例で明確にできますか?


11
このApplleのドキュメントでは、この質問のソリューションを実装する手順の概要を説明しています。http://developer.apple.com/library/ios/#documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html
ChrisP

@ChrisPこのリンクは、iOS 4.0では更新されていないことを示しています
Bae

このコードは役に立ちます: gist.github.com/TimMedcalf/9505416
landonandrey

以下のURL従って、それが動作します:stackoverflow.com/questions/48922266/...
ベンカテッシュG

回答:


126

UIViewControllerの代わりにUITableViewControllerを使用すると、自動的に使用されます。


13
試してみて、機能していないことを発見しましたか?それとも、ソリューションが単純すぎて信じられないでしょうか?UIViewControllerの代わりにUITableViewControllerを拡張するだけで、テキストフィールドが最初のレスポンダーになるたびに、テキストフィールドを含むセルがキーボードの上にスクロールします。追加のコードは必要ありません。
Sam Ho

3
はい、しかし特にiPadでは、UITableViewControllerを使用しないでこれを行う方法が必要です。
ボブ・スプリン

13
明確にするために、特にiPadでは、テーブルビューを使用するたびにフルスクリーンである必要があると言うのは合理的な答えではありません。それを行わない素晴らしいアプリの例の大群があります。たとえば、iPadの連絡先アプリを含む、Apple独自のものの多く。
ボブ・スプリン

32
[super viewWillAppear:YES]をオーバーライドすると機能しません。それ以外は、うまくいくはずです。
Rambatino、2014年

18
viewWillAppear:(BOOL)animatedをオーバーライドする場合は、[super viewWillAppear:animated]を呼び出すことを忘れないでください。:)
–MédéricPetit 2015

93

スクロールを実行する関数は、はるかに簡単です。

- (void) textFieldDidBeginEditing:(UITextField *)textField {
    UITableViewCell *cell;

    if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
    // Load resources for iOS 6.1 or earlier
        cell = (UITableViewCell *) textField.superview.superview;

    } else {
        // Load resources for iOS 7 or later
        cell = (UITableViewCell *) textField.superview.superview.superview; 
       // TextField -> UITableVieCellContentView -> (in iOS 7!)ScrollView -> Cell!
    }
    [tView scrollToRowAtIndexPath:[tView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

それでおしまい。まったく計算はありません。


2
そして、なぜですか?!UITableViewScrollPositionTopをUITableViewScrollPositionMiddleに置き換えるだけです。もちろん、UITableViewを再スケーリングして、表示領域を調整するだけです。
Mihai Damian

3
キーボードが表示されたときのUITableViewControllerは、テーブルビューのサイズ変更の世話をしている場合に動作していないよう:コントローラが可視サイズ削減contentInsetを求めていたときに明らかに考慮されていない、visibleRowsまたはindexPathsForVisibleRows
ジュリアンD.

16
テーブルビューの最後の数行では機能しません。キーボードは、キーボードの上にスクロールできないすべての行を覆い隠します。
Alex Zavatone 2014年

3
自動スクロール動作をテーブルの最後の数行で機能させるには、これらの行が編集を開始するタイミングを検出し、特定の高さの空白のビューでテーブルビューの最後にフッターを追加します。これにより、テーブルビューでセルを正しい場所にスクロールできます。
Sammio2 14年

10
superviewの呼び出しのチェーンを介してセルに到達することは、実際にセルに到達していることを確認しない限り、信頼できません。stackoverflow.com/a/17757851/1371070およびstackoverflow.com/a/17758021/1371070
Cezar

70

私はそれが一般的なものと非常によく似ていることをしています。コードに固有の何かを計算する必要はありません。コードの備考を確認してください:

MyUIViewController.h

@interface MyUIViewController: UIViewController <UITableViewDelegate, UITableViewDataSource>
{
     UITableView *myTableView;
     UITextField *actifText;
}

@property (nonatomic, retain) IBOutlet UITableView *myTableView;
@property (nonatomic, retain) IBOutlet UITextField *actifText;

- (IBAction)textFieldDidBeginEditing:(UITextField *)textField;
- (IBAction)textFieldDidEndEditing:(UITextField *)textField;

-(void) keyboardWillHide:(NSNotification *)note;
-(void) keyboardWillShow:(NSNotification *)note;

@end

MyUIViewController.m

@implementation MyUIViewController

@synthesize myTableView;
@synthesize actifText;

- (void)viewDidLoad 
{
    // Register notification when the keyboard will be show
    [[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(keyboardWillShow:)
                                          name:UIKeyboardWillShowNotification
                                          object:nil];

    // Register notification when the keyboard will be hide
    [[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(keyboardWillHide:)
                                          name:UIKeyboardWillHideNotification
                                          object:nil];
}

// To be link with your TextField event "Editing Did Begin"
//  memoryze the current TextField
- (IBAction)textFieldDidBeginEditing:(UITextField *)textField
{
    self.actifText = textField;
}

// To be link with your TextField event "Editing Did End"
//  release current TextField
- (IBAction)textFieldDidEndEditing:(UITextField *)textField
{
    self.actifText = nil;
}

-(void) keyboardWillShow:(NSNotification *)note
{
    // Get the keyboard size
    CGRect keyboardBounds;
    [[note.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue: &keyboardBounds];

    // Detect orientation
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGRect frame = self.myTableView.frame;

    // Start animation
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:0.3f];

    // Reduce size of the Table view 
    if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
        frame.size.height -= keyboardBounds.size.height;
    else 
        frame.size.height -= keyboardBounds.size.width;

    // Apply new size of table view
    self.myTableView.frame = frame;

    // Scroll the table view to see the TextField just above the keyboard
    if (self.actifText)
      {
        CGRect textFieldRect = [self.myTableView convertRect:self.actifText.bounds fromView:self.actifText];
        [self.myTableView scrollRectToVisible:textFieldRect animated:NO];
      }

    [UIView commitAnimations];
}

-(void) keyboardWillHide:(NSNotification *)note
{
    // Get the keyboard size
    CGRect keyboardBounds;
    [[note.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue: &keyboardBounds];

    // Detect orientation
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGRect frame = self.myTableView.frame;

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:0.3f];

    // Increase size of the Table view 
    if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
        frame.size.height += keyboardBounds.size.height;
    else 
        frame.size.height += keyboardBounds.size.width;

    // Apply new size of table view
    self.myTableView.frame = frame;

    [UIView commitAnimations];
}

@end

Swift 1.2+バージョン:

class ViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var activeText: UITextField!
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: Selector("keyboardWillShow:"),
            name: UIKeyboardWillShowNotification,
            object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: Selector("keyboardWillHide:"),
            name: UIKeyboardWillHideNotification,
            object: nil)
    }

    func textFieldDidBeginEditing(textField: UITextField) {
        activeText = textField
    }

    func textFieldDidEndEditing(textField: UITextField) {
        activeText = nil
    }

    func keyboardWillShow(note: NSNotification) {
        if let keyboardSize = (note.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            var frame = tableView.frame
            UIView.beginAnimations(nil, context: nil)
            UIView.setAnimationBeginsFromCurrentState(true)
            UIView.setAnimationDuration(0.3)
            frame.size.height -= keyboardSize.height
            tableView.frame = frame
            if activeText != nil {
                let rect = tableView.convertRect(activeText.bounds, fromView: activeText)
                tableView.scrollRectToVisible(rect, animated: false)
            }
            UIView.commitAnimations()
        }
    }

    func keyboardWillHide(note: NSNotification) {
        if let keyboardSize = (note.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            var frame = tableView.frame
            UIView.beginAnimations(nil, context: nil)
            UIView.setAnimationBeginsFromCurrentState(true)
            UIView.setAnimationDuration(0.3)
            frame.size.height += keyboardSize.height
            tableView.frame = frame
            UIView.commitAnimations()
        }
    }
}

通知を使用して、デバイスの向きを組み込んでいるときにキーボードの高さを取得するのは素晴らしいことでした。:私はこの使用していたので、スクロール部分が、何らかの理由で私のために仕事をしませんでした[tableView scrollToRowAtIndexPath: indexPath atScrollPosition: UITableViewScrollPositionMiddle animated: YES];
テーバー

7
これがここでの最良の答えだと思います。非常にきれいな。2つだけ:1)viewDidLoadが[super viewDidLoad]を呼び出していないこと、および2)frame.size.heightの行でいくつかのタブバーの計算を行わなければなりませんでした。そうでなければ完璧!ありがとう。
toxaq

3
toxaqが説明する変更は次のとおりです。MyAppDelegate *appDelegate = (MyAppDelegate*)[[UIApplication sharedApplication] delegate]; CGFloat tabBarHeight = appDelegate.tabBarController.tabBar.frame.size.height; 次に、キーボードの高さを使用する場合は常に、キーボードの高さからtabBarHeightを減算します。
Steve N

1
ユーザーがテキストフィールドをタップすると、完全に機能します。しかし、ユーザーがリターンキーを押さずに別のテキストフィールドをタップすると、テーブルビューのサイズが縮小されます。
Bhavin Ramani 2016

1
@BhavinRamaniは同意しました。キーボードが既に表示されているかどうかを記憶し、不要な場合はコードの再実行をスキップする単純なブール型プロパティを追加しました。
Dirty Henry

46

BartłomiejSemańczykソリューションに基づくSwift 3の最も簡単なソリューション:

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self, selector: #selector(CreateEditRitualViewController.keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(CreateEditRitualViewController.keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardDidHide, object: nil)
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

// MARK: Keyboard Notifications

@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardHeight = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height {
        tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0)
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    UIView.animate(withDuration: 0.2, animations: {
        // For some reason adding inset in keyboardWillShow is animated by itself but removing is not, that's why we have to use animateWithDuration here
        self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
    })
}

細かい詳細...のNotification代わりに使用NSNotificationすると、より「スウィフト3-y」になる:-)
Nicolas Miari

これは、navbarがある場合の再配置に役立ちます-UIView.animateをthis if letで囲みます-if let frame = self.navigationController?.navigationBar.frame {let y = frame.size.height + frame.origin.y}
Sean Dev

回転が発生すると、読み込みに問題が発生し、テーブルビューを手動でスクロールすると一部のセルが消えます
jothikenpachi

良い解決策ありがとう!注-removeObserverを実行する必要はありません。
Nick McConnell 2017年

44

私も同じ問題を抱えていましたが、1つのビューにしか表示されないことに気付きました。そこで、コントローラーの違いを探し始めました。

スクロール動作が設定されていることがわかりました - (void)viewWillAppear:(BOOL)animatedスーパーインスタンスに。

したがって、次のように実装してください。

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    // your code
}

また、UIViewControllerまたはを使用するかどうかは関係ありませんUITableViewController。をUITableViewでself.viewのサブビューとして配置することで確認しましたUIViewController。それは同じ振る舞いでした。呼び出し[super viewWillAppear:animated];が欠落している場合、ビューはスクロールできませんでした。


1
これはうまくいきました。なぜ人々はUITableViewが私に代わってそれをするだろうと言って、これがそれを解決したのかと思っていました。ありがとう!
olivaresF 2013年

5
私もこの問題を抱えていましたが、この答えが一番上になるはずです!
Amiel Martin

私は自分でそれを理解しようとするのに多くの時間を失いました...ありがとう;)
budidino 14

+1は少し泣き始めました。その行はありましたが、[tableViewController viewWillAppear:animated]も必要でした。UITableViewControllerをUIViewControllerに追加しているためです。これ以上の涙はありません:)
colin lamarre 14

41

ここで投稿全体を読んでいないので、これを見逃したかもしれませんが、思いついたのは一見単純そうです。私はこれを絞り込みにかけたわけではありませんが、すべての状況でテストしましたが、問題なく動作するようです。

キーボードの高さでテーブルビューのcontentInsetを調整し、セルを一番下までスクロールします。

- (void)keyboardWasShown:(NSNotification *)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
    self.myTableView.contentInset = contentInsets;
    self.myTableView.scrollIndicatorInsets = contentInsets;

    [self.myTableView scrollToRowAtIndexPath:self.currentField.indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}

そしてもちろん

- (void)keyboardWasHidden:(NSNotification *)aNotification
{
    [UIView animateWithDuration:.3 animations:^(void) 
    {
        self.myTableView.contentInset = UIEdgeInsetsZero;
        self.myTableView.scrollIndicatorInsets = UIEdgeInsetsZero;
    }];
}

これは単純すぎるのですか?私は何かを逃していますか?これまでのところ、それは私にとってはうまく機能していますが、私が言ったように、私はそれを絞り器に通していません...


IMO、これが最良のソリューションです。私が変更するのは、ハードコードされた期間が[aNotification.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue]
Andy

とてもシンプルです。しかし、私が見つけた1つの問題はcontentInset、スクロールの境界の変更をアニメーション化せず、急激に変更しないことです。
オタク2014年

これは私にとって最善の方法でしたが、いくつかの問題があります。1)「currentField.indexPath」をどこで取得できるかわからないため、indexPath.rowをフィールドのタグとして保存し、後でindexPathを作成する必要がありました。2)テーブル上部の行では機能せず、画面外にスクロールします。currentFieldのindexPathが画面に収まるサイズより大きい場合にのみスクロールするコードを追加する必要がありました。3)横長の場合、iPadでは(高さの代わりに)kbSize.Widthを使用する必要がありました
Travis M.

申し訳ありませんが、私たちは自分のコードに慣れすぎて、時々忘れてしまいますよね?currentFieldは、私が働いている現在のテキストフィールドであり、indexPathは私がこれは何であるセルを知っているので、単にNSIndexPathを追加することをクラスに追加した拡張機能です。
mickm

これは、テーブルのプロパティを変更するだけでフレームを移動するのではなく、進むべき道です。
Nextorlg 2014

35

私はAppleのアプリの振る舞いと一致する解決策を思いついたと思います。

最初に、viewWillAppear:キーボード通知をサブスクライブします。これにより、キーボードがいつ表示または非表示になるかがわかり、システムがキーボードのサイズを通知しますが、viewWillDisappear:で登録を解除することを忘れないでください。

[[NSNotificationCenter defaultCenter]
    addObserver:self
       selector:@selector(keyboardWillShow:)
           name:UIKeyboardWillShowNotification
         object:nil];
[[NSNotificationCenter defaultCenter]
    addObserver:self
       selector:@selector(keyboardWillHide:)
           name:UIKeyboardWillHideNotification
         object:nil];

以下のようなメソッドを実装して、キーボードが表示されたら可視領域に一致するようにtableViewのサイズを調整します。ここでは、キーボードの状態を個別に追跡しているので、フィールドを変更するたびに通知が届くので、tableViewをいつフルハイトに戻すかを選択できます。keyboardWillHide:の実装を忘れないでください。tableViewのサイズを修正するために適切な場所を選択してください。

-(void) keyboardWillShow:(NSNotification *)note
{
    CGRect keyboardBounds;
    [[note.userInfo valueForKey:UIKeyboardBoundsUserInfoKey] getValue: &keyboardBounds];
    keyboardHeight = keyboardBounds.size.height;
    if (keyboardIsShowing == NO)
    {
        keyboardIsShowing = YES;
        CGRect frame = self.view.frame;
        frame.size.height -= keyboardHeight;

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationBeginsFromCurrentState:YES];
        [UIView setAnimationDuration:0.3f];
        self.view.frame = frame;
        [UIView commitAnimations];
    }
}

これがスクロールビットです。最初にいくつかのサイズを調べてから、表示領域のどこにいるかを確認し、スクロールする四角形を、テキストフィールドの中央の上または下の半分のビューになるように設定しますビューのどこにあるか。この場合、UITextFieldsの配列とそれらを追跡する列挙型があるため、rowHeightに行番号を掛けると、この外部ビュー内のフレームの実際のオフセットがわかります。

- (void) textFieldDidBeginEditing:(UITextField *)textField
{
    CGRect frame = textField.frame;
    CGFloat rowHeight = self.tableView.rowHeight;
    if (textField == textFields[CELL_FIELD_ONE])
    {
        frame.origin.y += rowHeight * CELL_FIELD_ONE;
    }
    else if (textField == textFields[CELL_FIELD_TWO])
    {
        frame.origin.y += rowHeight * CELL_FIELD_TWO;
    }
    else if (textField == textFields[CELL_FIELD_THREE])
    {
        frame.origin.y += rowHeight * CELL_FIELD_THREE;
    }
    else if (textField == textFields[CELL_FIELD_FOUR])
    {
        frame.origin.y += rowHeight * CELL_FIELD_FOUR;
    }
    CGFloat viewHeight = self.tableView.frame.size.height;
    CGFloat halfHeight = viewHeight / 2;
    CGFloat midpoint = frame.origin.y + (textField.frame.size.height / 2);
    if (midpoint < halfHeight)
    {
        frame.origin.y = 0;
        frame.size.height = midpoint;
    }
    else
    {
        frame.origin.y = midpoint;
        frame.size.height = midpoint;
    }
    [self.tableView scrollRectToVisible:frame animated:YES];
}

これはかなりうまくいくようです。


素晴らしい解決策。投稿いただきありがとうございます。
Alex Reynolds、

2
UIKeyboardBoundsUserInfoKeyiOS 3.2以降は非推奨です。現在のすべてのiOSリリース≥3.0で機能する以下の私のソリューションを参照してください。/ @ iPhoneDev
Ortwin Gentz

これは必要以上に複雑でした。@ user91083の答えはシンプルでうまくいきました。
Richard Brightwell、

1
このソリューションには小さな問題があります。keyboardWillShowはAFTER textFieldDidBeginEditingと呼ばれるため、セルにスクロールしたい場合、tableViewのフレームはまだ変更されていないため、機能しません
HiveHicks

35

を使用できるUITableViewController場合は、機能を無料で利用できます。ただし、これはオプションではない場合もあります。特に、だけでなく、複数のビューが必要な場合などですUITableView

ここで紹介するソリューションには、iOS≥4では機能しないもの、iPadまたは横向きモードで機能しないもの、Bluetoothキーボードで機能しないもの(スクロールが不要なもの)、機能しないものがあります。複数のテキストフィールドを切り替えるときに機能します。したがって、ソリューションを選択する場合は、必ずこれらのケースをテストしてください。これは、私たちが解決策で使用 使用してInAppSettingsKit

- (void)_keyboardWillShow:(NSNotification*)notification {
    if (self.navigationController.topViewController == self) {
        NSDictionary* userInfo = [notification userInfo];

        // we don't use SDK constants here to be universally compatible with all SDKs ≥ 3.0
        NSValue* keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardBoundsUserInfoKey"];
        if (!keyboardFrameValue) {
            keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardFrameEndUserInfoKey"];
        }

        // Reduce the tableView height by the part of the keyboard that actually covers the tableView
        CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
        if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
            windowRect = IASKCGRectSwap(windowRect);
        }
        CGRect viewRectAbsolute = [_tableView convertRect:_tableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
        if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
            viewRectAbsolute = IASKCGRectSwap(viewRectAbsolute);
        }
        CGRect frame = _tableView.frame;
        frame.size.height -= [keyboardFrameValue CGRectValue].size.height - CGRectGetMaxY(windowRect) + CGRectGetMaxY(viewRectAbsolute);

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
        [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
        _tableView.frame = frame;
        [UIView commitAnimations];

        UITableViewCell *textFieldCell = (id)((UITextField *)self.currentFirstResponder).superview.superview;
        NSIndexPath *textFieldIndexPath = [_tableView indexPathForCell:textFieldCell];

        // iOS 3 sends hide and show notifications right after each other
        // when switching between textFields, so cancel -scrollToOldPosition requests
        [NSObject cancelPreviousPerformRequestsWithTarget:self];

        [_tableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
    }
}

- (void) scrollToOldPosition {
  [_tableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

- (void)_keyboardWillHide:(NSNotification*)notification {
    if (self.navigationController.topViewController == self) {
        NSDictionary* userInfo = [notification userInfo];

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
        [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
        _tableView.frame = self.view.bounds;
        [UIView commitAnimations];

        [self performSelector:@selector(scrollToOldPosition) withObject:nil afterDelay:0.1];
    }
}   

ここだ、クラスの完全なコード InAppSettingsKitでは。これをテストするには、上記のシナリオをテストできる「完全なリスト」子ペインを使用します。


定数の代わりに文字列を使用することが有用かどうかはわかりません。Appleが何らかの理由で内部的に文字列を変更するという考えに至った場合、ソリューションが機能しなくなったためです。それはdeprecated.Iが思うになったとき同様に、あなたは警告を取得していない

@iPortable:それは理想的ではない、私は知っている。3.0以上のすべてのバージョンで動作するより良いソリューションを提案できますか?
Ortwin Gentz 2010

1
チャームのように機能しますが、UIInterfaceOrientationPortraitUpsideDownでは機能しません。次に、高さの削減の計算も上下逆にする必要があります。
Klaas

iPadとSimulator(4.3)で、これは非常に目立つ視覚的な不具合です。使用するにはあまりにも目立ちます。:(
ボブ・スプリン

このソリューションでは、画面の下部にあるツールバーを考慮に入れています。
pdemarest 2011

24

Swiftの最も簡単なソリューション:

override func viewDidLoad() {
    super.viewDidLoad()

    searchBar?.becomeFirstResponder()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MyViewController.keyboardWillShow(_:)), name: UIKeyboardDidShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MyViewController.keyboardWillHide(_:)), name: UIKeyboardDidHideNotification, object: nil)
}

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func keyboardWillShow(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        if let keyboardHeight = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue.size.height {
            tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0)
        }
    }
}

func keyboardWillHide(notification: NSNotification) {
    UIView.animateWithDuration(0.2, animations: { self.table_create_issue.contentInset = UIEdgeInsetsMake(0, 0, 0, 0) })
    // For some reason adding inset in keyboardWillShow is animated by itself but removing is not, that's why we have to use animateWithDuration here
    }

完全に機能し、必要な最小限の計算。この回答を完成させるために、テーブルのインセットを復元するコードをいくつか追加しました。
Vitalii

最高のソリューションに感謝します。ここにSwift 3バージョンを投稿しました:stackoverflow.com/a/41040630/1064438
squall2022

これまでに見た非常に完璧な解決策、私は他のものを試しましたが、いくつかの問題があります。あなたのソリューションはiOS 10.2で完璧に動作します。
Wangdu Lin、

8

私は皆さんがそれらすべてを読んでいる解決策をすでに持っていることを望みます。しかし、私は次のように私の解決策を見つけました。既にのセルがあることを期待していますUITextField。したがって、準備では、行インデックスをテキストフィールドのタグに保持します。

cell.textField.tag = IndexPath.row;

以下のようactiveTextFieldUITextField、グローバルスコープを持つのインスタンスを作成します。

@interface EditViewController (){

    UITextField *activeTextField;

}

だから、今あなたは私のコードを最後にコピーして貼り付けるだけです。また、追加することを忘れないでくださいUITextFieldDelegate

#pragma mark - TextField Delegation

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{

    activeTextField = textField;

    return YES;
}

- (void)textFieldDidEndEditing:(UITextField *)textField{

    activeTextField = nil;

}

キーボードを登録する notifications

#pragma mark - Keyboard Activity

- (void)registerForKeyboardNotifications

{

    [[NSNotificationCenter defaultCenter] addObserver:self

                                         selector:@selector(keyboardWasShown:)

                                             name:UIKeyboardDidShowNotification object:nil];



    [[NSNotificationCenter defaultCenter] addObserver:self

                                         selector:@selector(keyboardWillBeHidden:)

                                             name:UIKeyboardWillHideNotification object:nil];



}

キーボードを処理しNotificationsます。

UIKeyboardDidShowNotificationが送信されたときに呼び出されます。

- (void)keyboardWasShown:(NSNotification*)aNotification

{

    NSDictionary* info = [aNotification userInfo];

    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);

    [self.tableView setContentInset:contentInsets];

    [self.tableView setScrollIndicatorInsets:contentInsets];

    NSIndexPath *currentRowIndex = [NSIndexPath indexPathForRow:activeTextField.tag inSection:0];

    [self.tableView scrollToRowAtIndexPath:currentRowIndex atScrollPosition:UITableViewScrollPositionTop animated:YES];

}

ときに呼び出されます UIKeyboardWillHideNotificationが送信されたれます

- (void)keyboardWillBeHidden:(NSNotification*)aNotification

{

    UIEdgeInsets contentInsets = UIEdgeInsetsZero;

    [self.tableView setContentInset:contentInsets];

    [self.tableView setScrollIndicatorInsets:contentInsets];

}

もう1つ残っています。 registerForKeyboardNotificationsViewDidLoad次のようにメソッドをinメソッドにます。

- (void)viewDidLoad {

    [super viewDidLoad];

    // Registering keyboard notification

    [self registerForKeyboardNotifications];

    // Your codes here...

}

完了しtextFieldsました。キーボードに隠れないようにしてください。


6

いくつかの回答(特にOrtwin Gentz、ユーザー98013)と別の投稿の空白を組み合わせて入力すると、縦向きまたは横向きモードのiPadでSDK 4.3のボックスをそのまま使用できます。

@implementation UIView (FindFirstResponder)
- (UIResponder *)findFirstResponder
{
  if (self.isFirstResponder) {        
    return self;     
  }

  for (UIView *subView in self.subviews) {
    UIResponder *firstResponder = [subView findFirstResponder];
    if (firstResponder != nil) {
      return firstResponder;
    }
  }

  return nil;
}
@end

@implementation MyViewController

- (UIResponder *)currentFirstResponder {
  return [self.view findFirstResponder];
}

- (IBAction)editingEnded:sender {
  [sender resignFirstResponder];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
  [textField resignFirstResponder];
  return NO;
}

- (void)textFieldDidBeginEditing:(UITextField *)textField {
  UITableViewCell *cell = (UITableViewCell*) [[textField superview] superview];
  [_tableView scrollToRowAtIndexPath:[_tableView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

- (void)keyboardWillShow:(NSNotification*)notification {
  if ([self currentFirstResponder] != nil) {
    NSDictionary* userInfo = [notification userInfo];

    // we don't use SDK constants here to be universally compatible with all SDKs ≥ 3.0
    NSValue* keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardBoundsUserInfoKey"];
    if (!keyboardFrameValue) {
      keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardFrameEndUserInfoKey"];
    }

    // Reduce the tableView height by the part of the keyboard that actually covers the tableView
    CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
    CGRect viewRectAbsolute = [_tableView convertRect:_tableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
    CGRect frame = _tableView.frame;
    if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
      windowRect = CGRectMake(windowRect.origin.y, windowRect.origin.x, windowRect.size.height, windowRect.size.width);
      viewRectAbsolute = CGRectMake(viewRectAbsolute.origin.y, viewRectAbsolute.origin.x, viewRectAbsolute.size.height, viewRectAbsolute.size.width);
    }
    frame.size.height -= [keyboardFrameValue CGRectValue].size.height - CGRectGetMaxY(windowRect) + CGRectGetMaxY(viewRectAbsolute);

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
    _tableView.frame = frame;
    [UIView commitAnimations];

    UITableViewCell *textFieldCell = (id)((UITextField *)self.currentFirstResponder).superview.superview;
    NSIndexPath *textFieldIndexPath = [_tableView indexPathForCell:textFieldCell];

    // iOS 3 sends hide and show notifications right after each other
    // when switching between textFields, so cancel -scrollToOldPosition requests
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
    _topmostRowBeforeKeyboardWasShown = [[_tableView indexPathsForVisibleRows] objectAtIndex:0];
    [_tableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
  }
}

- (void) scrollToOldPosition {
  [_tableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

- (void)keyboardWillHide:(NSNotification*)notification {
  if ([self currentFirstResponder] != nil) {

    NSDictionary* userInfo = [notification userInfo];

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
    _tableView.frame = self.view.bounds;
    [UIView commitAnimations];

    [self performSelector:@selector(scrollToOldPosition) withObject:nil afterDelay:0.1];
  }
}   

@end

私はこのコードをiOS 4.xでうまく使用しましたが、iOS5では_topmostRowBeforeKeyboardWasShownがその時点ですでに解放されているため、scrollToOldPositionでクラッシュします。解決策はまだわかりません。おそらくオブジェクトではなくインデックスを覚えておいてください。
Thomas Tempelmann、2011年

5

uitableviewを使用してテキストフィールドを配置する場合(Jeff Lamarcheから)、デリゲートメソッドを使用してテーブルビューをスクロールするだけです。

(注:テキストフィールドは、テーブルビューの行と同じインデックスを持つ配列に保存されます)

- (void) textFieldDidBeginEditing:(UITextField *)textField
    {

        int index;
        for(UITextField *aField in textFields){

            if (textField == aField){
                index = [textFields indexOfObject:aField]-1;
            }
        }

         if(index >= 0) 
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];

        [super textFieldDidBeginEditing:textField];
    }

tableViewフレームは更新しません。次に、キーボードが表示されているときのscrollBarsとスクロール動作が正しくありません。私の解決策を参照してください。
Ortwin Gentz

5

キーボード通知は機能しますが、そのためのAppleのサンプルコードは、スクロールビューがウィンドウのルートビューであると想定しています。通常はそうではありません。正しいオフセットを得るには、タブバーなどを補正する必要があります。

思ったより簡単です。以下は、UITableViewControllerで使用するコードです。2つのインスタンス変数、hiddenRectとkeyboardShownがあります。

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification {
    if (keyboardShown)
        return;

    NSDictionary* info = [aNotification userInfo];

    // Get the frame of the keyboard.
    NSValue *centerValue = [info objectForKey:UIKeyboardCenterEndUserInfoKey];
    NSValue *boundsValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
    CGPoint keyboardCenter = [centerValue CGPointValue];
    CGRect keyboardBounds = [boundsValue CGRectValue];
    CGPoint keyboardOrigin = CGPointMake(keyboardCenter.x - keyboardBounds.size.width / 2.0,
                                         keyboardCenter.y - keyboardBounds.size.height / 2.0);
    CGRect keyboardScreenFrame = { keyboardOrigin, keyboardBounds.size };


    // Resize the scroll view.
    UIScrollView *scrollView = (UIScrollView *) self.tableView;
    CGRect viewFrame = scrollView.frame;
    CGRect keyboardFrame = [scrollView.superview convertRect:keyboardScreenFrame fromView:nil];
    hiddenRect = CGRectIntersection(viewFrame, keyboardFrame);

    CGRect remainder, slice;
    CGRectDivide(viewFrame, &slice, &remainder, CGRectGetHeight(hiddenRect), CGRectMaxYEdge);
    scrollView.frame = remainder;

    // Scroll the active text field into view.
    CGRect textFieldRect = [/* selected cell */ frame];
    [scrollView scrollRectToVisible:textFieldRect animated:YES];

    keyboardShown = YES;
}


// Called when the UIKeyboardDidHideNotification is sent
- (void)keyboardWasHidden:(NSNotification*)aNotification
{
    // Reset the height of the scroll view to its original value
    UIScrollView *scrollView = (UIScrollView *) self.tableView;
    CGRect viewFrame = [scrollView frame];
    scrollView.frame = CGRectUnion(viewFrame, hiddenRect);

    keyboardShown = NO;
}

UIKeyboardCenterEndUserInfoKeyまたUIKeyboardBoundsUserInfoKey、iOS 3.2以降は非推奨です。現在のすべてのiOSリリース≥3.0で機能する以下の私のソリューションを参照してください。
Ortwin Gentz、2010

5

を使用する場合Three20は、autoresizesForKeyboardプロパティを使用します。ビューコントローラーの-initWithNibName:bundleメソッドで設定するだけです

self.autoresizesForKeyboard = YES

これは次のことを処理します:

  1. キーボード通知をリッスンし、テーブルビューのフレームを調整する
  2. 最初のレスポンダーまでスクロール

完了しました。


ここでThree20とは何ですか?それを指定できますか?
ムビンモール

5

私のアプローチ:

最初にUITextFieldをサブクラス化し、indexPathプロパティを追加します。cellFor ...メソッドで、indexPathプロパティを渡します。

次に、次のコードを追加します。

UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:textField.indexPath];

CGPoint cellPoint = [cell convertPoint:textField.center toView:self.tableView];
[UIView animateWithDuration:0.3 animations:^(void){self.tableView.contentOffset = CGPointMake(0, cellPoint.y-50);}];

textFieldShould / WillBegin ... etc。

キーボードが消えたら、次のようにして反転させる必要があります。

[UIView animateWithDuration:0.3 animations:^(void){self.tableView.contentOffset = CGPointMake(0, 0);}];

4

より合理化されたソリューション。それはUITextFieldデリゲートメソッドに滑り込むので、UIKeyboard通知をいじる必要はありません。

実装上の注意:

kSettingsRowHeight-UITableViewCellの高さ。

offsetTargetとoffsetThresholdは、kSettingsRowHeightに基づいています。別の行の高さを使用する場合は、それらの値をポイントのyプロパティに設定します。[alt:別の方法で行オフセットを計算します。]

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
CGFloat offsetTarget    = 113.0f; // 3rd row
CGFloat offsetThreshold = 248.0f; // 6th row (i.e. 2nd-to-last row)

CGPoint point = [self.tableView convertPoint:CGPointZero fromView:textField];

[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.2];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];

CGRect frame = self.tableView.frame;
if (point.y > offsetThreshold) {
    self.tableView.frame = CGRectMake(0.0f,
                      offsetTarget - point.y + kSettingsRowHeight,
                      frame.size.width,
                      frame.size.height);
} else if (point.y > offsetTarget) {
    self.tableView.frame = CGRectMake(0.0f,
                      offsetTarget - point.y,
                      frame.size.width,
                      frame.size.height);
} else {
    self.tableView.frame = CGRectMake(0.0f,
                      0.0f,
                      frame.size.width,
                      frame.size.height);
}

[UIView commitAnimations];

return YES;

}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];

[UIView beginAnimations:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.2];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];

CGRect frame = self.tableView.frame;
self.tableView.frame = CGRectMake(0.0f,
                  0.0f,
                  frame.size.width,
                  frame.size.height);

[UIView commitAnimations];

return YES;

}


4

使用UITextField's delegate方法:

迅速

func textFieldShouldBeginEditing(textField: UITextField) -> bool {
  let txtFieldPosition = textField.convertPoint(textField.bounds.origin, toView: yourTableViewHere)
  let indexPath = yourTablViewHere.indexPathForRowAtPoint(txtFieldPosition)
  if indexPath != nil {
     yourTablViewHere.scrollToRowAtIndexPath(indexPath!, atScrollPosition: .Top, animated: true)
  }
  return true
}

Objective-C

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
  CGPoint txtFieldPosition = [textField convertPoint:CGPointZero toView: yourTablViewHere];
  NSLog(@"Begin txtFieldPosition : %@",NSStringFromCGPoint(txtFieldPosition));
  NSIndexPath *indexPath = [yourTablViewHere indexPathForRowAtPoint:txtFieldPosition];

  if (indexPath != nil) {
     [yourTablViewHere scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
  }
  return YES;
}

こんにちは、これをSwiftで機能させるための問題があります。UITableViewCellに接続された私のUITextFields。このコードをUIViewController内に実装すると、UITextFieldsにアクセスできなくなります。何か案は?
Vetuka 2017年

4

Swift 4.2完全なソリューション

プロトコルのセットでGISTを作成しましたキーボードが表示、非表示、または変更されたときに余分なスペースを追加することで作業を簡素化をて。

特徴

  • キーボードフレームの変更で正しく動作します(たとえば、絵文字→通常のキーボードのようにキーボードの高さが変更されます)。
  • UITableViewの例に対するTabBarおよびToolBarのサポート(他の例では、誤ったインセットを受け取ります)。
  • 動的アニメーション期間(ハードコードされていません)。
  • 目的に応じて簡単に変更できるプロトコル指向のアプローチ。

使用法

スクロールビューを含むビューコントローラーでの基本的な使用例(もちろん、テーブルビューもサポートされています)。

class SomeViewController: UIViewController {
  @IBOutlet weak var scrollView: UIScrollView!

  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    addKeyboardFrameChangesObserver()
  }

  override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    removeKeyboardFrameChangesObserver()
  }
}

extension SomeViewController: ModifableInsetsOnKeyboardFrameChanges {
  var scrollViewToModify: UIScrollView { return scrollView }
}

コア:フレーム変更オブザーバー

プロトコルKeyboardChangeFrameObserverは、キーボードフレームが変更されるたびにイベントを発生させます(表示、非表示、フレーム変更を含む)。

  1. に電話addKeyboardFrameChangesObserver()するviewWillAppear()または同様のメソッドをます。
  2. removeKeyboardFrameChangesObserver()atviewWillDisappear()または同様のメソッドを呼び出します。

実装:スクロールビュー

ModifableInsetsOnKeyboardFrameChangesprotocolはUIScrollView、コアプロトコルのサポートを追加します。キーボードフレームが変更されると、スクロールビューのインセットが変更されます。

クラスはスクロールビューを設定する必要があります。キーボードフレームが変更されると、インセットが増減します。

var scrollViewToModify: UIScrollView { get }

3

テーブルにはテキストフィールドがあるので、実際の最善の方法はテーブルのサイズを変更することです。tableView.frameの高さをキーボードのサイズ(約165ピクセルだと思う)だけ低く設定し、次の場合にもう一度拡張する必要があります。キーボードが閉じられます。

ユーザーがスクロールしないようにする場合は、オプションでその時点でのtableViewのユーザー操作を無効にすることもできます。


これを2番目にし、UIKeyboardWillShowNotificationに登録して、キーボードのサイズを動的に検出します。
ベンザド

ただし、通知オブジェクトによって返された番号は機能しません。または、少なくとも2.2では発生しませんでした。返された数値は正しくなく、高さを正しく調整するために165の値をハードコーディングする必要がありました(5〜10ピクセル
ずれていました

2

これは完璧に動作し、iPadでも動作します。

- (BOOL)textFieldShouldReturn:(UITextField *)textField 
{

    if(textField == textfield1){
            [accountName1TextField becomeFirstResponder];
        }else if(textField == textfield2){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield3 becomeFirstResponder];

        }else if(textField == textfield3){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield4 becomeFirstResponder];

        }else if(textField == textfield4){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield5 becomeFirstResponder];

        }else if(textField == textfield5){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:3 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield6 becomeFirstResponder];

        }else if(textField == textfield6){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:4 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield7 becomeFirstResponder];

        }else if(textField == textfield7){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:5 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield8 becomeFirstResponder];

        }else if(textField == textfield8){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:6 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textfield9 becomeFirstResponder];

        }else if(textField == textfield9){
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:7 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
            [textField resignFirstResponder];
        }

各テキストフィールドの特殊なケースを比較して使用するのはなぜですか?セルのNSIndexPathから各テキストフィールドにIDを付け、その厄介なifステートメントを2行のコードに変更します。本当にcellForRowAtIndexPathを呼び出してから、セルからtextFieldを取得します。
Alex Zavatone 2014年

実際、この状況がiOSでどれほど不安定であるかを考えると、「完全に巻き戻され、途方もなくリテラル」なコードをこの状況で記述しても問題ないと思います。
Fattie

この答えを考えると、6年以上前に与えられました。
WrightsCS

2

私はほとんど同じアプローチを試し、同じためのよりシンプルで小さなコードを思いつきました。IBOutlet iTextViewを作成し、IBのUITextViewに関連付けました。

 -(void)keyboardWillShow:(NSNotification *)notification
    {
        NSLog(@"Keyboard");
        CGRect keyFrame = [[[notification userInfo]objectForKey:UIKeyboardFrameEndUserInfoKey]CGRectValue];

        [UIView beginAnimations:@"resize view" context:nil];
        [UIView setAnimationCurve:1];
        [UIView setAnimationDuration:1.0];
        CGRect frame = iTableView.frame;
        frame.size.height = frame.size.height -  keyFrame.size.height;
        iTableView.frame = frame;
        [iTableView scrollRectToVisible:frame animated:YES];
        [UIView commitAnimations];

    }

2

したがって、これらの現在のソリューションを使用しようとする(そして完全に失敗する)数時間の過酷な作業の後、私はようやく物事をうまく機能させ、新しいアニメーションブロックを使用するように更新しました。私の答えは、上記のOrtwinの答えに完全に基づいています。

したがって、何らかの理由で上記のコードは私にとってはうまく機能しませんでした。私のセットアップは他のセットアップとかなり似ているように見えましたが、iPadまたは4.3を使用していたためか、わかりません。それは奇抜な数学をしていて、私のテーブルビューを画面から放っていました。

私のソリューションの最終結果を参照してください:http : //screencast.com/t/hjBCuRrPC ください //screencast.com/t/hjBCuRrPC(写真は無視してください。:-P)

だから私はOrtwinがやっていることの要点を手に入れましたが、テーブルビューのorigin.y&size.heightとキーボードの高さを合計するための計算方法を変更しました。その結果からウィンドウの高さを引くと、どれだけの交差点が進んでいるかがわかります。0よりも大きい場合(一部重複がある場合)、フレームの高さのアニメーションを実行します。

さらに、1)アニメーションが完了するまでセルまでスクロールするのを待機すること、および2)キーボードを非表示にするときにUIViewAnimationOptionBeginFromCurrentStateオプションを使用することによって解決された、いくつかの再描画の問題がありました。

注意すべきいくつかの事柄。

  • _topmostRowBeforeKeyboardWasShown&_originalFrameは、ヘッダーで宣言されたインスタンス変数です。
  • self.guestEntryTableViewは私のtableViewです(私は外部ファイルにいます)
  • IASKCGRectSwapは、フレームの座標を反転するためのOrtwinの方法です。
  • 少なくとも50ピクセルが表示される場合にのみ、tableViewの高さを更新します
  • UIViewControllerにいないのでself.viewがないので、tableViewを元のフレームに戻すだけです。

繰り返しますが、もし私がOrtwinがその核心を提供しなかったら、私はこの答えに近づくことはなかっただろう。これがコードです:

- (IBAction)textFieldDidBeginEditing:(UITextField *)textField
{
    self.activeTextField = textField;

    if ([self.guestEntryTableView indexPathsForVisibleRows].count) {
        _topmostRowBeforeKeyboardWasShown = (NSIndexPath*)[[self.guestEntryTableView indexPathsForVisibleRows] objectAtIndex:0];
    } else {
        // this should never happen
        _topmostRowBeforeKeyboardWasShown = [NSIndexPath indexPathForRow:0 inSection:0];
        [textField resignFirstResponder];
    }
}

- (IBAction)textFieldDidEndEditing:(UITextField *)textField
{
    self.activeTextField = nil;
}

- (void)keyboardWillShow:(NSNotification*)notification {
    NSDictionary* userInfo = [notification userInfo];

    NSValue* keyboardFrameValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];

    // Reduce the tableView height by the part of the keyboard that actually covers the tableView
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
    CGRect viewRectAbsolute = [self.guestEntryTableView convertRect:self.guestEntryTableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
    CGRect keyboardFrame = [keyboardFrameValue CGRectValue];
    if (UIInterfaceOrientationLandscapeLeft == orientation ||UIInterfaceOrientationLandscapeRight == orientation ) {
        windowRect = IASKCGRectSwap(windowRect);
        viewRectAbsolute = IASKCGRectSwap(viewRectAbsolute);
        keyboardFrame = IASKCGRectSwap(keyboardFrame);
    }

    // fix the coordinates of our rect to have a top left origin 0,0
    viewRectAbsolute = FixOriginRotation(viewRectAbsolute, orientation, windowRect.size.width, windowRect.size.height);

    CGRect frame = self.guestEntryTableView.frame;
    _originalFrame = self.guestEntryTableView.frame;

    int remainder = (viewRectAbsolute.origin.y + viewRectAbsolute.size.height + keyboardFrame.size.height) - windowRect.size.height;

    if (remainder > 0 && !(remainder > frame.size.height + 50)) {
        frame.size.height = frame.size.height - remainder;
        float duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
        [UIView animateWithDuration: duration
                        animations:^{
                            self.guestEntryTableView.frame = frame;
                        }
                        completion:^(BOOL finished){
                            UITableViewCell *textFieldCell = (UITableViewCell*) [[self.activeTextField superview] superview];
                            NSIndexPath *textFieldIndexPath = [self.guestEntryTableView indexPathForCell:textFieldCell];
                            [self.guestEntryTableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
                        }];
    }

}

- (void)keyboardWillHide:(NSNotification*)notification {
    NSDictionary* userInfo = [notification userInfo];
    float duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    [UIView animateWithDuration: duration
                          delay: 0.0
                        options: (UIViewAnimationOptionBeginFromCurrentState)
                     animations:^{
                         self.guestEntryTableView.frame = _originalFrame;
                     }
                     completion:^(BOOL finished){
                         [self.guestEntryTableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
                     }];

}   

#pragma mark CGRect Utility function
CGRect IASKCGRectSwap(CGRect rect) {
    CGRect newRect;
    newRect.origin.x = rect.origin.y;
    newRect.origin.y = rect.origin.x;
    newRect.size.width = rect.size.height;
    newRect.size.height = rect.size.width;
    return newRect;
}

CGRect FixOriginRotation(CGRect rect, UIInterfaceOrientation orientation, int parentWidth, int parentHeight) {
    CGRect newRect;
    switch(orientation)
    {
        case UIInterfaceOrientationLandscapeLeft:
            newRect = CGRectMake(parentWidth - (rect.size.width + rect.origin.x), rect.origin.y, rect.size.width, rect.size.height);
            break;
        case UIInterfaceOrientationLandscapeRight:
            newRect = CGRectMake(rect.origin.x, parentHeight - (rect.size.height + rect.origin.y), rect.size.width, rect.size.height);
            break;
        case UIInterfaceOrientationPortrait:
            newRect = rect;
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            newRect = CGRectMake(parentWidth - (rect.size.width + rect.origin.x), parentHeight - (rect.size.height + rect.origin.y), rect.size.width, rect.size.height);
            break;
    }
    return newRect;
}

フレームを更新する前にビューの座標系を修正するFixOriginRotation関数を追加しました。これが、最初に問題が発生した理由の1つだと思います。デバイスと共に回転するiOSウィンドウ座標系を認識していませんでした!
Bob Spryn、2011

2

このソリューションは私にとってはうまくいきます、ラインに注意してください

[tableView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height+160) animated:YES];

あなたに合うように160の値を変更することができます

- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGRect bkgndRect = activeField.superview.frame;
                        bkgndRect.size.height += kbSize.height;
     [activeField.superview setFrame:bkgndRect];
     [tableView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height+160) animated:YES];
}

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
   activeField = textField;
}
-(void)textFieldDidEndEditing:(UITextField *)textField
 {
     activeField = nil;
 }
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    tableView.contentInset = contentInsets;
    tableView.scrollIndicatorInsets = contentInsets;
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGRect bkgndRect = activeField.superview.frame;
    //bkgndRect.size.height += kbSize.height;
    [activeField.superview setFrame:bkgndRect];
    [tableView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height) animated:YES];
}

2

非常に興味深いディスカッションスレッド、私は同じ問題に直面しました。

  1. 私はカスタムセルを使用しており、テキストフィールドはその中にありました。
  2. 要件を満たすためにUIViewControllerを使用する必要があったため、UITableViewControllerを利用できません。
  3. テーブルセルにフィルター/並べ替えの条件を設定しました。つまり、urセルはインデックスパスを常に変更し、追跡し続けているため、どれも役に立ちません。

だから、ここのスレッドを読んで私のバージョンを実装してください。これにより、iPadで横向きモードでコンテンツを押し上げることができました。ここにコードがあります(これはばかげたことではありませんが、問題は修正されました)まず、カスタムセルクラスにデリゲートが必要です。これは、編集の開始時に、テキストフィールドをurビューコントローラーに送信し、そこにactivefield = theTextFieldを設定します

//横置きモードのみを処理するように実装されています

- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbValue = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGRect aRect = myTable.frame;

    CGSize kbSize = CGSizeMake(kbValue.height, kbValue.width);

    aRect.size.height -= kbSize.height+50;
// This will the exact rect in which your textfield is present
        CGRect rect =  [myTable convertRect:activeField.bounds fromView:activeField];
// Scroll up only if required
    if (!CGRectContainsPoint(aRect, rect.origin) ) {


            [myTable setContentOffset:CGPointMake(0.0, rect.origin.y) animated:YES];

    }


}

// UIKeyboardWillHideNotificationが送信されたときに呼び出されます

- (void)keyboardWillHide:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    myTable.contentInset = contentInsets;
    myTable.scrollIndicatorInsets = contentInsets;
    NSDictionary* info = [aNotification userInfo];
    CGSize kbValue = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGSize kbSize = CGSizeMake(kbValue.height, kbValue.width);
    CGRect bkgndRect = activeField.superview.frame;
    bkgndRect.size.height += kbSize.height;
    [activeField.superview setFrame:bkgndRect];
    [myTable setContentOffset:CGPointMake(0.0, 10.0) animated:YES];
}

-anoop4real


2

GoogleとStack Overflowで見つかった大量のソリューションを参照した後、私はこのような問題を自分で解決しました。

まず、UIScrollViewのIBOutletが設定されていることを確認してから、Apple Doc:Keyboard Managementをよく見てください。最後に、背景をスクロールできてもキーボードがテキストフィールドを覆っている場合は、次のコードを確認してください。

// If active text field is hidden by keyboard, scroll it so it's visible
// Your application might not need or want this behavior.
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.height;

if (aRect.size.height < activeField.frame.origin.y+activeField.frame.size.height) {

    CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y+activeField.frame.size.height-aRect.size.height);

    [scrollView setContentOffset:scrollPoint animated:YES];

この作品とAppleの主な違いは、if条件にあります。Appleのスクロール距離の計算と、キーボードでカバーされたテキストフィールドが正しくないかどうかの条件が正しいと思うので、上記のように変更しました。

機能するかどうか教えてください


2

Swift でのUITableViewCellのUITextFieldのGet indexPathからのテキストフィールドの正確なポイントを使用したSwiftの例 :

func textFieldDidBeginEditing(textField: UITextField) {
    let pointInTable = textField.convertPoint(textField.bounds.origin, toView: self.accountsTableView)
    let textFieldIndexPath = self.accountsTableView.indexPathForRowAtPoint(pointInTable)
    accountsTableView.scrollToRowAtIndexPath(textFieldIndexPath!, atScrollPosition: .Top, animated: true)
}

1

別の簡単な方法(1つのセクションでのみ機能)

//cellForRowAtIndexPath
UItextField *tf;
[cell addSubview:tf];
tf.tag = indexPath.row;
tf.delegate = self;

//textFieldDidBeginEditing:(UITextField *)text
[[self.tableView scrollToRowsAtIndexPath:[NSIndexPath indexPathForRow:text.tag in section:SECTIONINTEGER] animated:YES];

1

UITableViewがUITableViewControllerではなくUITableViewControllerのサブクラスによって管理されており、テキストフィールドデリゲートがUITableViewControllerである場合、すべてのスクロールを自動的に管理する必要があります-これらの他のすべてのコメントは実際に実装するのが非常に困難です。

良い例については、Appleのサンプルコードプロジェクト:TaggedLocationsをご覧ください。

自動的にスクロールすることがわかりますが、これを行うコードはありません。このプロジェクトにはカスタムのテーブルビューセルも含まれるため、それをガイドとして使用してアプリケーションをビルドすると、望ましい結果が得られるはずです。


1

これが私がこの作品を作成した方法です。これは、Sam HoとMarcel Wの回答を組み合わせたものであり、自分の気難しいコードに加えた独自のバグ修正の一部です。UITableViewControllerを使用していました。キーボードが表示されているときに、テーブルのサイズが正しく変更されるようになりました。

1)viewDidLoad私が追加した:

self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight;

2)私は、呼び出すために忘れていたsuperに相当するviewWillAppearawakeFromNib。これらを追加しました。


1

UITableViewController確かに、自動的にスクロールを行います。を使用する場合との違いUIViewControllerは、を使用するNavigationController場合、を使用してプログラムでNavbar-Buttonitemを作成する必要があることですTableViewController

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.