iPhoneキーボードカバーUITextField


120

私は、Interface Builderで、UIViewで、ビューの下部近くにテキストフィールドがあるあります。アプリを実行してそのフィールドにテキストを入力しようとすると、キーボードがフィールドの上にスライドし、キーボードをもう一度非表示にするまで、入力している内容がわかりません。

他の誰かがこの問題に遭遇し、親ビューをスクロール可能にしたり、テキストフィールドを画面のさらに上に移動したりせずに問題を解決する良い方法を見つけましたか?


回答:


290

通常の解決策は、フィールド(およびその上のすべて)をアニメーションで上にスライドさせ、終了したら下に戻すことです。テキストフィールドと他のいくつかの項目を別のビューに配置し、ビューを1つの単位としてスライドする必要がある場合があります。(私はこれらを「テクトニクスプレート」のように「プレート」と呼びますが、それは私だけです)。しかし、ここでは、ファンシーを取得する必要がない場合の一般的な考え方を示します。

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    [self animateTextField: textField up: YES];
}


- (void)textFieldDidEndEditing:(UITextField *)textField
{
    [self animateTextField: textField up: NO];
}

- (void) animateTextField: (UITextField*) textField up: (BOOL) up
{
    const int movementDistance = 80; // tweak as needed
    const float movementDuration = 0.3f; // tweak as needed

    int movement = (up ? -movementDistance : movementDistance);

    [UIView beginAnimations: @"anim" context: nil];
    [UIView setAnimationBeginsFromCurrentState: YES];
    [UIView setAnimationDuration: movementDuration];
    self.view.frame = CGRectOffset(self.view.frame, 0, movement);
    [UIView commitAnimations];
}

12
コードへのリンクを投稿しなかったが、コード自体は気に入った。
Ben Coffman

2
素晴らしいコード。機能させるために編集する必要はありませんでした。おかげで〜
ジェームズ

5
以下のようにすべての画面をカバーすると便利です。const int MovementDistance = textField.frame.origin.y / 2; //必要に応じて微調整
conecon 2012

3
「iOS 4以降のアプリケーションを作成している場合は、代わりにコンテンツをアニメーション化するためにブロックベースのメソッドを使用する必要があります。」:から参照developer.apple.com/library/ios/#documentation/windowsviews/...
マチュー

1
これを発見し、それは同じ問題について議論developer.apple.com/Library/ios/documentation/StringsTextFonts/...
のUnom

38

これは私にとってuitextfieldsをスライドさせるのに不思議に働きました

特に、テキストフィールドの位置に応じてスライドアニメーションの距離を計算できるという利点があります。


これは素晴らしい。テキストフィールドごとに「移動距離」定数を選択する必要はありません。これは自動的に計算されます。
jlstrecker

最高のソリューションです。驚異的なメカニズム!
マルキー2012年

1
iPadでも動作します。PORTRAIT_KEYBOARD_HEIGHT = 264およびLANDSCAPE_KEYBOARD_HEIGHT = 352を更新しました。素晴らしいリンクです。ありがとう。
Khon Lieu 2013年

上記のリンクはちょうど私の日を作りました!実装がとても簡単で、これまでのところ問題なく動作します!
JimmyJammed 2013

1
これが、このトピックに関する説明です。他のチュートリアルでは、テーブルビュー、スクロールビューなどを使用します。これは実際には、他の複雑なことをしなくても機能します。このソースを共有していただきありがとうございます。
Renexandro 2014

28

IQKeyboardManagerは、コード追加せずにこれを行います。関連するソースファイルをプロジェクトにドラッグアンドドロップするだけで済みます。IQKeyboardManagerは、デバイスの向き自動UIToolbarの管理keyboardDistanceFromTextFieldなど、ご想像以上の機能もサポートしています。

ここに画像の説明を入力してください

制御フローチャートは次のとおりです。 制御フローチャート

ステップ1: -のグローバルな通知を追加しましたUITextFieldUITextViewUIKeyboardシングルトンクラスで。私はそれをIQKeyboardManagerと呼びました

Step2:-見つかった場合UIKeyboardWillShowNotificationUITextFieldTextDidBeginEditingNotificationまたはUITextViewTextDidBeginEditingNotification通知の場合topMostViewControllerUIWindow.rootViewController階層からインスタンスを取得しようとします。適切に明らかにためにUITextField/ UITextViewその上に、topMostViewController.viewのフレームを調整する必要があります。

Step3:-topMostViewController.view最初に応答したUITextField/ に対する計算された予想移動距離UITextView

ステップ4: -移動topMostViewController.view.frame予想移動距離に応じてダウン/アップ。

ステップ5:-見つかった場合UIKeyboardWillHideNotificationUITextFieldTextDidEndEditingNotificationまたはUITextViewTextDidEndEditingNotification通知のtopMostViewController場合は、UIWindow.rootViewController階層からインスタンスを再度取得してみます。

Step6:-計算された乱れた距離をtopMostViewController.view元の位置に戻す必要があります。

Step7:-topMostViewController.view.frame妨害された距離に従って復元されます。

ステップ8:-アプリのロード時にインスタンス化されたシングルトンIQKeyboardManagerクラスインスタンス。アプリ内のすべてのUITextField/ UITextViewは、予想される移動距離に従って自動的に調整されます。

それで全部です


受け入れられた答えは私にとってはうまくいきませんでした。しかし、これはそうです。
学習者2014

@ZaEeMZaFaR IQKeyboardManagerもiPad用に最適化されています。ライブラリgithub repoで問題を開いて、iPadでの問題を示すデモプロジェクトをアップロードできますか?
Mohd Iftekhar Qurashi

返信ありがとうございます。問題が解決しない場合は、コメントする前に、IQKeyboardManagerはユニバーサルデバイス用ではないと考えていました。
ZaEeM ZaFaR 2015

さらに調査すると、シミュレータ上のiPadで正常に機能しますが、実際のiPadデバイスでは機能しません。iPhone(デバイス+シミュレータ)でも完全に正常に動作します。問題は何でしょうか?
ZaEeM ZaFaR 2015

前に述べたように、iOSとデバイスバージョンの詳細を含むデモプロジェクトを含むgithub repoで問題を提起する必要があります。そうすれば、問題を調査できます。
Mohd Iftekhar Qurashi

7

Amagrammerの回答を拡張するために、サンプルクラスを次に示します。

LoginViewController.h

@interface LoginViewController : UIViewController <UITextFieldDelegate> {

}

@property (nonatomic, retain) IBOutlet UITextField    *emailTextField;
@property (nonatomic, retain) IBOutlet UITextField    *passwordTextField;

「UITextFieldDelegate」を実装していることに注意してください

LoginViewController.m

@implementation LoginViewController
@synthesize emailTextField=_emailTextField;
@synthesize passwordTextField=_passwordTextField;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        //Register to receive an update when the app goes into the backround
        //It will call our "appEnteredBackground method
        [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(appEnteredBackground)
                                                 name:UIApplicationDidEnterBackgroundNotification
                                               object:nil];
    }
    return self;
}


- (void) animateTextField: (UITextField*) textField up: (BOOL) up
{
    const int movementDistance = 80; // tweak as needed
    const float movementDuration = 0.3f; // tweak as needed

    int movement = (up ? -movementDistance : movementDistance);

    [UIView beginAnimations: @"anim" context: nil];
    [UIView setAnimationBeginsFromCurrentState: YES];
    [UIView setAnimationDuration: movementDuration];
    self.view.frame = CGRectOffset(self.view.frame, 0, movement);
    [UIView commitAnimations];
}

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    [self animateTextField: textField up: YES];
}


- (void)textFieldDidEndEditing:(UITextField *)textField
{
    [self animateTextField: textField up: NO];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    [textField resignFirstResponder];
    return YES;
}
//This is called when the app goes into the background.
//We must reset the responder because animations will not be saved
- (void)appEnteredBackground{
    [self.emailTextField resignFirstResponder];
    [self.passwordTextField resignFirstResponder];
}

言及するための+1 UIApplicationDidEnterBackgroundNotification、それ以外の場合、ホームボタンを押してアプリに戻ると、下に移動し、醜くてバグが多くなります。
Adil Soomro 2013年

7

公式ソリューションはどうですか:キーボードの下にあるコンテンツの移動

コンテンツを調整するには、通常、1つ以上のビューのサイズを一時的に変更し、テキストオブジェクトが表示されたままになるようにビューを配置します。キーボードでテキストオブジェクトを管理する最も簡単な方法は、UIScrollViewオブジェクト(またはUITableViewのようなそのサブクラスの1つ)内に埋め込むことです。キーボードが表示されたら、スクロールビューのコンテンツ領域をリセットし、目的のテキストオブジェクトを所定の位置にスクロールするだけです。したがって、UIKeyboardDidShowNotificationに応答して、ハンドラーメソッドは次のことを行います。

  1. キーボードのサイズを取得します。
  2. キーボードの高さによって、スクロールビューの下部コンテンツインセットを調整します。
  3. ターゲットテキストフィールドをスクロールして表示します。
// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
            selector:@selector(keyboardWasShown:)
            name:UIKeyboardDidShowNotification object:nil];

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

}

// Called when the UIKeyboardDidShowNotification is sent.
- (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);
    scrollView.contentInset = contentInsets;
    scrollView.scrollIndicatorInsets = contentInsets;

    // If active text field is hidden by keyboard, scroll it so it's visible
    // Your app might not need or want this behavior.
    CGRect aRect = self.view.frame;
    aRect.size.height -= kbSize.height;
    if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) {
        [self.scrollView scrollRectToVisible:activeField.frame animated:YES];
    }
}

// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    scrollView.contentInset = contentInsets;
    scrollView.scrollIndicatorInsets = contentInsets;
}

この公式ソリューションは、コントロールにラップされています。ここを参照してください。- stackoverflow.com
a/17707094/1582217

アイデアは良いですが、 'contentInset'プロパティはここでは役に立ちません。cozcontentInsetはパディング効果を提供するだけです。
。cozcontentInset

@Raj、それがIQKeyboardManagerで確認できるケースかもしれませんが、contentInsetプロパティの問題に関する公式のIQKeyboardManager githubリポジトリで誰も問題を開いていないので、それは機能していると思います。
Mohd Iftekhar Qurashi 2014

7

UITableView textFieldセルでも同じ問題に直面しています。この問題を解決するには、次のメソッドを実装してキーボード通知をリッスンします。

ここで通知のオブザーバー:

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

以下の関数を使用してこれらの通知を処理します。

(void)keyboardWasShown:(NSNotification*)aNotification 
(void)keyboardWillBeHidden:(NSNotification*)aNotification 

1
リンクが壊れています。将来的には独立したソリューションを含めることを検討してください!
miek 2013

5

これをチェックしてください。面倒はありません。

このソリューションは非常にきちんとしています。ストーリーボードを使用している場合は、テキストフィールドをに追加UIScrollViewTPKeyboardAvoidingScollView、クラスをに変更するだけです。スクロールビューは、キーボードが表示されたときにそれを検出し、適切な距離でキーボードの上に移動するように拡張されています。それはあなたの独立しているので、それは完璧なソリューションUIViewControllerです。必要なことはすべて上記のクラス内で行われます。Michael Tysonらに感謝します。

TPKeyboardAvoiding


@NANNAV-回答を変更する提案をするときはコメントを提供してください。
セキュリティハウンド

5

以下は、Amagrammerの回答の迅速なバージョンです。また、ビューを邪魔にならないように移動する前にキーボードのサイズを知る必要があるため、UIKeyboardWillShowNotificationイベントを使用したバリエーション。

var keyboardHeight:CGFloat = 0

override func viewDidLoad() {
    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillChange:", name: UIKeyboardWillShowNotification, object: nil)
}

func textFieldDidBeginEditing(textField: UITextField) {
    //keyboardWillChange (below) is used instead of textFieldDidBeginEditing because textFieldDidBeginEditing
    //is called before the UIKeyboardWillShowNotification necessary to determine the keyboard height.
}

func textFieldDidEndEditing(textField: UITextField) {
    animateTextField(false)
}

func animateTextField(textFieldUp:Bool) {
    let movementDistance:CGFloat = keyboardHeight
    let movementDuration = 0.3

    let movement:CGFloat = (textFieldUp ? -movementDistance : movementDistance)

    UIView.beginAnimations("anim", context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(movementDuration)
    self.view.frame = CGRectOffset(self.view.frame, 0, movement)
    UIView.commitAnimations()
}

func keyboardWillChange(notification:NSNotification) {
    let keyboardRect:CGRect = ((notification.userInfo![UIKeyboardFrameEndUserInfoKey])?.CGRectValue)!
    keyboardHeight = keyboardRect.height
    animateTextField(true)
}

4

あいまいにせずにテキストフィールドを編集することの素晴らしいウォークスルーがありました(リンクは今は死んでいます、ここにWaybackリンクがあります:https : //web.archive.org/web/20091123074029/http : //acts-as-geek.blogspot.com/2009/ 11 / editing-textfields-without-obscuring.html)。既存のものUIViewをに移動する方法を示しますUIScrollViewし、キーボードが表示されたときに自動的にスクロールます。

の下にUIScrollViewコントロール(などUITabBar)がある場合の正しい高さを計算するために少し更新しましたUIScrollBaruiviewを更新する投稿を参照してください。


2

Xcode5、iOS7を使用したソリューションは次のとおりです。

UITextfieldDelegateおよびアニメーションブロックを使用します。

これはViewControllerのほぼすべてのコードですが、私と同じようにデリゲートパターンにまだ慣れていない人のためのデリゲートコードを含めたかったのです。また、textviewから離れてタップしたときにキーボードを非表示にするコードも含めました。

ビュー(ボタン、テキストフィールドなど)を必要な高さまで移動できるので、それらを元の位置に戻します(+100、後で-100)。

@interface ViewController () <UITextFieldDelegate>
@property (strong, nonatomic) IBOutlet UITextField *MyTextField;

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.MyTextField.delegate = self;

}

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
      NSLog(@"text began editing");

      CGPoint MyPoint = self.MyTextField.center;

      [UIView animateWithDuration:0.3
                    animations:^{

                    self.MyTextField.center = CGPointMake(MyPoint.x, MyPoint.y - 100);
                                }];
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
     NSLog(@"text ENDED editing");

     CGPoint MyPoint = self.MyTextField.center;

     [UIView animateWithDuration:0.3
                 animations:^{

     self.MyTextField.center = CGPointMake(MyPoint.x, MyPoint.y + 100);
                             }];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
     [self.view endEditing:YES];
}

1

テキストフィールドがクリックされたときにビュー全体の位置を(x、y)から(x、y-keybaardHeight)に移動し、キーボードが閉じられたときに元の位置に戻す方法は、ビューと同じように少し奇妙に見えるかもしれません表示されます(アニメーション化しても問題ないかもしれません)。

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    CGRect frame=self.view.frame;
    frame.origin=CGPointMake(x...//set point here
    self.view.frame=frame;
}

いいえ、ちがいます。ユーザーが最初のテキストフィールドをタップすると、表示領域の上に表示されます。
lolol

0

Amagrammerのソリューションに加えて、cocos2dをポートレートモードで使用している場合は、次の行を変更します。

self.view.frame = CGRectOffset(self.view.frame, 0, movement);

これに:

[CCDirector sharedDirector].openGLView.frame = CGRectOffset([CCDirector sharedDirector].openGLView.frame, movement, 0);

cocos2dを横モードで使用している場合は、上記の変更を行い、up値をtextFieldDidBeginEditing:とに切り替えます。textFieldDidEndEditing:

- (void)textFieldDidBeginEditing:(UITextField *)textField {
    [self animateTextField:textField up:NO];
}

- (void)textFieldDidEndEditing:(UITextField *)textField {
    [self animateTextField:textField up:YES];
}

0

私は同じ問題を抱えていて、GTKeyboardHelperが簡単な方法であることがわかりました。

プロジェクトにフレームワークをドラッグアンドドロップした後、ヘッダーファイルを含めます。サンプルプロジェクトをダウンロードして開き、「キーボードヘルパー」オブジェクトをxibのオブジェクトセクションからプロジェクトのインターフェイスビルダーのオブジェクトセクションにドラッグします。

すべてのビューをドラッグアンドドロップして、「キーボードヘルパー」の子にします。


0

プロジェクトで使用するドラッグアンドドロップフレームワーク。ファーストレスポンダーの外側をタップしたとき、またはスクロールしたときの自動却下をサポートしています。

GTKeyboardHelper


0

必要に応じて、ビューを上下にスライドするだけです。

- (void)textFieldDidEndEditing:(UITextField *)textField {
    self.currentTextField = nil;
    [self animateTextField: textField up: NO];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [self.currentTextField resignFirstResponder];
    return YES;
}

- (void) animateTextField:(UITextField*) textField up:(BOOL)up {
    const int movementDistance = 80; // tweak as needed
    const float movementDuration = 0.3f; // tweak as needed

    int movement = (up ? -movementDistance : movementDistance);

    [UIView animateWithDuration:movementDuration animations:^{
        self.view.frame = CGRectOffset(self.view.frame, 0, movement);
    }];
}

設定することを忘れてはいけないselfUITextFieldDelegateし、実際のテキストフィールドとしてdelegate

(Ammamagrammerのおかげで、これはアニメーション用のブロックを使用したより短い回答です)


0

あなたが望むなら、私は何か他のものを持っています。ここでのポイントは、編集しているテキストフィールドのUIViewの中心を設定することです。

その前に、あなたは保存する必要がINITIAL_CENTERを通り、するCGPoint self.view.centerとあなたから、INITIAL_VIEWとしてCGRect constのプロパティでself.view.frameから。

次のようなメソッドを作成できます。

- (void) centerOn: (CGRect) fieldFrame {

    // Set up the center by taking the original view center
    CGPoint center = CGPointMake(INITIAL_CENTER.x,
                             INITIAL_CENTER.y - ((fieldFrame.origin.y + fieldFrame.size.height/2) - INITIAL_CENTER.y));


    [UIView beginAnimations:@"centerViewOnField" context:nil];
    [UIView setAnimationDuration:0.50];

    if (CGRectEqualToRect(fieldFrame,INITIAL_VIEW)) {
        self.view.frame = INITIAL_VIEW;
        [self.view setCenter:INITIAL_CENTER];
    } else {
        [self.view setCenter:center];
    }


    [UIView commitAnimations];
}

次に、UITextFieldDelegateでcenterOn:(CGRect)を呼び出す必要があります以下のメソッドでます。

textFieldDidBeginEditing:(UITextField *)、パラメーターとして、中央に配置するテキストフィールドのフレーム。

そして、あなたはあなたのキーボードを閉じるあなたのイベントハンドラでそれを呼び出す必要があります、

textFieldDidEndEditing:(UITextField *)は、INITIAL_VIEWをcenterOn:(CGRect)のパラメーターとして設定することで実現できます。


0

iOSの新しいバージョン(6.1以降、場合によっては以前のバージョン)では、少なくともUITableViewの基になるビューは、キーボードがポップアップしたときに自動的に縮小すると思います。したがって、そのビューでテキストフィールドを表示するだけです。でinit

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWasShown:)
                                             name:UIKeyboardDidShowNotification
                                           object:nil];

次に:

- (void)keyboardWasShown:(NSNotification*)notification
{
    // Scroll the text field into view so it's not under the keyboard.
    CGRect rect = [self.tableView convertRect:inputView.bounds fromView:inputView];
    [self.tableView scrollRectToVisible:rect animated:YES];
}

0

https://github.com/ZulwiyozaPutra/Shift-Keyboard-Exampleこのソリューションがお役に立てば幸いです。これらはすべてSwift 3で作成されています。

//
//  ViewController.swift
//  Shift Keyboard Example
//
//  Created by Zulwiyoza Putra on 11/23/16.
//  Copyright © 2016 Zulwiyoza Putra. All rights reserved.
//

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {
    
    
    //connecting textfield from storyboard
    @IBOutlet weak var textField: UITextField!
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        subscribeToKeyboardNotifications()
    }
    
    override func viewDidAppear(_ animated: Bool) {
        self.textField.delegate = self
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        unsubscribeFromKeyboardNotifications()
    }
    
    //Hide keyboard after finished editing
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }
    
    //Setup view before keyboard appeared
    func keyboardWillAppear(_ notification:Notification) {
        view.frame.origin.y = 0 - getKeyboardHeight(notification)
    }
    
    //Setup view before keyboard disappeared
    func keyboardWillDisappear(_ notification: Notification) {
        view.frame.origin.y = 0
    }
    
    //Getting keyboard height
    func getKeyboardHeight(_ notification:Notification) -> CGFloat {
        let userInfo = notification.userInfo
        let keyboardSize = userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue // of CGRect
        return keyboardSize.cgRectValue.height
    }
    
    //Subscribing to notifications to execute functions
    func subscribeToKeyboardNotifications() {
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillAppear(_:)), name: .UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillDisappear(_:)), name: .UIKeyboardWillHide, object: nil)
    }
    
    //Unsubscribing from notifications
    func unsubscribeFromKeyboardNotifications() {
        NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
        NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
    }
    
}

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