モーダルViewControllerプレゼンテーションスタイルがUIModalPresentationFormSheetの場合、iPadキーボードは閉じません。


214

注意:

iOS 4.3以降の解決策については、承認された回答(上位投票ではない)を参照してください。

この質問は、iPadのキーボードで発見された動作に関するもので、ナビゲーションコントローラーのあるモーダルダイアログに表示された場合、その動作は却下されません。

基本的に、ナビゲーションコントローラーに次の行を表示すると、次のようになります。

navigationController.modalPresentationStyle = UIModalPresentationFormSheet;

キーボードは却下されません。この行をコメントアウトすると、キーボードは正常に消えます。

...

ユーザー名とパスワードの2つのtextFieldがあります。ユーザー名には[次へ]ボタンがあり、パスワードには[完了]ボタンがあります。これをモーダルナビゲーションコントローラーに表示しても、キーボードは消えません。

WORKS

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
[self.view addSubview:b.view];

動作しません

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
UINavigationController *navigationController = 
[[UINavigationController alloc]
 initWithRootViewController:b];
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
navigationController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:navigationController animated:YES];
[navigationController release];
[b release];

ナビゲーションコントローラー部分を削除し、それ自体でモーダルビューコントローラーとして「b」を表示すると、機能します。ナビゲーションコントローラーに問題がありますか?

WORKS

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
b.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:b animated:YES];
[b release];

WORKS

broken *b = [[broken alloc] initWithNibName:@"broken" bundle:nil];
UINavigationController *navigationController = 
    [[UINavigationController alloc]
         initWithRootViewController:b];
[self presentModalViewController:navigationController animated:YES];
[navigationController release];
[b release];

以下のSOの質問には、同じ問題を抱えているようだが、何の答えはありません。stackoverflow.com/questions/3019709/...
カレ

+1すばらしい説明ありがとうございます。しかし、私はその方法をどこに置く必要がありますか?モデルコントローラーを表示するためのコードを作成する場所では機能していないようです...
Lorenzo B

1
モーダルビューコントローラークラス自体に存在する必要があります。
Kalle

ありがとう。そうですか。UINavigationController授業用のカテゴリーに入れてみました。乾杯。
ロレンソB

私はこの質問についてあなたにとても感謝しています。それresignFirstResponderが実行されているのには驚きましたが、キーボードはまだ表示されています。私のシナリオ(navig contrllrを使用したpresentationFormSheet)は、あなたのシナリオとまったく同じです。トンありがとう!
sErVerdevIL 2013年

回答:


115

モーダルで表示されるビューコントローラーで、オーバーライドdisablesAutomaticKeyboardDismissalして返すだけNOです。

- (BOOL)disablesAutomaticKeyboardDismissal {
    return NO;
}

うん、4.3以降、そうなったようです。質問を更新します。ありがとう!
Kalle

2
これをナビゲーションコントローラーに追加する必要があります
pottedmeat

1
はい、NavigationControllerで上書きすると機能します。それが実際に私のために働いた唯一のものです。
James Laurenstin、

ライフセーバー!なぜAppleはこのようなことをするのですか?確かにデフォルトはNOであり、本当に必要な場合は変更できるようにする必要があります
SomaMan

UIViewController派生クラスでは機能せず、disablesAutomaticKeyboardDismissalが呼び出されることはありません
Jorge Arimany

172

これはアップルのエンジニアによって「意図したとおりに機能する」と分類されています。しばらく前に、このバグを報告しました。その理由は、ユーザーがモーダルフォームでデータを入力することがよくあるため、「役立つ」ようにして、通常はモーダルビュー内のさまざまな遷移によってキーボードが繰り返し表示/非表示になるキーボードを表示したままにすることです。

編集:開発者フォーラムでのAppleエンジニアの応答は次のとおりです:

たまたまあなたの見解はUIModalPresentationFormSheetスタイルで提示されましたか?頻繁な入出力アニメーションを回避するために、最初のレスポンダーがいない場合でも、キーボードが画面上に残ることがあります。これはバグではありません。

これは多くの人に問題を引き起こしています(私も含まれます)が、現時点ではそれを回避する方法はないようです。

更新:

iOS 4.3以降では、ビューコントローラに「-disablesAutomaticKeyboardDismissal」を実装してNOを返すことができます。

- (BOOL)disablesAutomaticKeyboardDismissal {
    return NO;
}

これで問題が解決します。


7
一時停止すごい。頭を上げてくれてありがとう。くそーりんご.. :(
Kalle

バグレポートをアップルに提出しましたか?私はID#8384423でこれを行いました。また、動作を再現するためのサンプルアプリケーションを提出しました。
シャギーフロッグ

3
iOS 4.3以降、この問題を修正するdisablesAutomaticKeyboardDismissalメソッドがあります。
Kalle

5
disablesAutomaticKeyboardDismissalメソッドを試してみましたが、それでも問題は解決しませんでした。解決方法は?
R. Dewi 2011

3
@Snips:モーダルフォームシートを表示するときに、これを返し、ナビゲーションコントローラとして使用するためにUINavigationControllerオーバーライドするサブクラスを作成する必要があります。以下の@ miha-hribarからの回答を参照してください。disablesAutomaticKeyboardDismissalNO
Pascal、

149

でモーダルを表示する場合は注意してくださいUINavigationController。次にdisablesAutomaticKeyboardDismissal、ビューコントローラではなくナビゲーションコントローラでを設定する必要があります。これをカテゴリで簡単に行うことができます。

ファイル:UINavigationController + KeyboardDismiss.h

#import <Foundation/Foundation.h>

@interface UINavigationController (KeyboardDismiss)

- (BOOL)disablesAutomaticKeyboardDismissal;

@end

ファイル:UINavigationController + KeyboardDismiss.m

#import "UINavigationController+KeyboardDismiss.h"

@implementation UINavigationController(KeyboardDismiss)

- (BOOL)disablesAutomaticKeyboardDismissal
{
    return NO;
}

@end

UINavigationControllerを使用するファイルにカテゴリをインポートすることを忘れないでください。


19
+1、最後に、この問題の不足している情報が強調表示されています。この問題を修正するには、ビューコントローラーdisablesAutomaticKeyboardDismissalUINavigationControllerはなくをオーバーライドする必要があります。
DarkDust、2011年

いいね!ちょうど私が必要としたもの。ありがとうございました。
ジャスティン

完璧です。公式ドキュメントからは明確ではありませんが、UINavigationControllerがレスポンダーチェーンにあるため、理にかなっています。すばらしい答えです。ありがとうございました!
imnk

1
UISplitViewControllerからモーダルダイアログを表示しています。上記のコードを試しましたが、UISplitViewControllerをUINavigationControllerに置き換えましたが、それでも機能しません。このメソッドはUISplitViewControllerでも機能しますか?
切り取り

6
カテゴリに複製メソッドを実装することはお勧めできません。どの実装が呼び出されるかを特定することはできません。そのため、せいぜい一貫性のない動作が予想されます。UINavigationControllerから継承し、カスタムクラスのメソッドをオーバーライドすることをお勧めします。
ショーンウッドワード2013

51

UIModalPresentationPageSheetプレゼンテーションスタイルを使用し、プレゼンテーション後すぐにサイズを変更することで、これを解決しました。そのようです:

viewController.modalPresentationStyle = UIModalPresentationPageSheet;
viewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:viewController animated:YES];
viewController.view.superview.autoresizingMask = 
    UIViewAutoresizingFlexibleTopMargin | 
    UIViewAutoresizingFlexibleBottomMargin;    
viewController.view.superview.frame = CGRectMake(
    viewController.view.superview.frame.origin.x,
    viewController.view.superview.frame.origin.y,
    540.0f,
    529.0f
);
viewController.view.superview.center = self.view.center;
[viewController release];

うーん...これは正確ではありません...サイズを変更するとモーダルがおかしくなります...それは新しいサイズのボックスまたは何かに収まるように内容を圧縮するようなものです...すべてがおかしく見えます。:(
toofah

これにも回転の問題があります...このモーダルがアップしているときに回転すると、フルページビューのように縮小/拡大します
toofah

2
ふつう、コードを編集して、回転時の縮小/拡大の問題に対処しました。スーパービューに上下のマージンを柔軟に設定するだけです。他の動作が表示されるかどうかはわかりません。
azdev

1
これは、このビューの上に他のビューをプッシュしない限りのみ機能します。UIModalPresentationPageSheet表示ビューの上にプッシュされたビューを閉じると、元のサイズに戻ります。
V1ru8 2011

出来た。しかし、ビュー内の単語は少しぼやけて見えます。理由はわかりません。
jeswang 2012

1

別のモーダル表示を切り替えると、キーボードが表示されなくなる場合があります。それはかわいくなく、アニメーション化されませんが、あなたはそれを無くすことができます。

修正があったらすばらしいですが、今のところこれでうまくいきます。あなたはそれをカテゴリーでくさびで止めてUIViewController、キーボードを消したいときにそれを呼び出すことができます:

@interface _TempUIVC : UIViewController
@end

@implementation _TempUIVC
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return YES;
}
@end

@implementation UIViewController (Helpers)

- (void)_dismissModalViewController {
    [self dismissModalViewControllerAnimated:NO];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];
    [self release];
}

- (void)forceKeyboardDismissUsingModalToggle:(BOOL)animated {
    [self retain];
    _TempUIVC *tuivc = [[_TempUIVC alloc] init];
    tuivc.modalPresentationStyle = UIModalPresentationCurrentContext;
    [self presentModalViewController:tuivc animated:animated];
    if (animated) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_dismissModalViewController) name:UIKeyboardDidHideNotification object:nil];
    } else
        [self _dismissModalViewController];
    [tuivc release];
}

@end

ただし、viewDidAppear / viewDidDisappearとこれらのすべてのメソッドが呼び出されるため、これには注意してください。私が言ったように、それはきれいではありませんが、動作します。

-アダム


1

イディオムをチェックするだけで、ユニバーサルアプリでこれを回避することもできます。iPadの場合は、キーボードを自動的にポップアップしないで、ユーザーが編集したいものをタップできるようにします。

最も良い解決策ではないかもしれませんが、それは非常に簡単で、次の主要なiOSリリースで壊れるような特別なハックは必要ありません:)


1

このコードをviewWillDisappearに配置します。現在のコントローラーのメソッドは、これを修正する別の方法です。

Class UIKeyboardImpl = NSClassFromString(@"UIKeyboardImpl");
id activeInstance = [UIKeyboardImpl performSelector:@selector(activeInstance)];
[activeInstance performSelector:@selector(dismissKeyboard)];

1

私はそれを見つけdisablesAutomaticKeyboardDismissaldisablesAutomaticKeyboardDismissal機能を追加することが私の場合うまくいきませんでしたUITextFieldモーダルダイアログで、。

スクリーンキーボードは消えません。

私の解決策は、ダイアログのすべてのテキスト入力コントロールを無効にしてから、関連するコントロールをほんの一瞬後に再度有効にすることでした。

iOS UITextFieldが有効になっているコントロールがないことを確認すると、キーボードが取り除かれるように見えます。


0

これを見たことがあると思いますが、コントローラークラスがUITextFieldデリゲートとして正しくフックされていることは間違いありませんよね?


自分で手動で設定すると、デリゲートメソッドが呼び出されるので、ええ。
Kalle

0

おそらく NOを返さないでください。だからそれは消えてしまうことができます。

そして、あなたもtextFieldShouldEndEditingYESを返していますか?

そして、なぜあなたは発砲し[nextResponder becomeFirstResponder]ますか?ごめんなさい、今見ます

また、すべての「編集可能」プロパティがFALSEに設定されているUITextViewもいくつかあります。

それらのどれも、たまたま、tag値がsecondField.tag+1ないと思いますか?もしそうなら、あなたは彼らに、最初のレスポンダーを辞任する代わりに、最初のレスポンダーになるように伝えています。if構造にNSLog()を入れるのもいいかもしれません。


1
いいえ=私が言えることから、改行を挿入しません。YESに設定しても修正されませんでした。
Kalle

1
UITextFieldは、定義上1行なので、改行にはあまり影響しません。したがって、ドキュメントに記載されているように、Return / Doneボタンを押す処理の詳細です。
mvds 2010

すべてが正しい方法で接続されていると確信していますか?NSLog("tf %x / method ...",textField);すべてのデリゲート関数に入れましたか?
mvds 2010

デリゲート関数は適切に呼び出されますが、デリゲートが適切に設定されていなかった場合は呼び出されません。そして、NSLogはEXC_BAD_ACCESSを提供します。また、XCodeで互換性のない型であることを警告します。
Kalle

ドー。申し訳ありませんが、私自身はそれを見るべきでした。私は.. COMMに自分自身を芥ますフォーマットするので、これらのNSLogsの結果と上記の答えを更新しました
カレ

0

UINavigationControllerで問題が発生している場合は、https://stackoverflow.com/a/10507689/321785で同様の質問に対する私の回答を参照して ください。

編集:私はこれをMiha Hribarのソリューションの改善と見なします(決定はどこで行われるのかのため)、UIViewControllerのカテゴリに関するPascalのコメントとは対照的です


0

完璧な解決策ではないかもしれませんが、機能します
[self.view endEditing:YES];
ボタンやジェスチャーがモーダルを提示するために実装されているところから


0
Swift 4.1:
extension UINavigationController {
   override open var disablesAutomaticKeyboardDismissal: Bool {
      return false
   }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.