アカベコマイリ

HEAR NOTHING SEE NOTHING SAY NOTHING

iOS 7 以降の UIAlertView カスタマイズ代替について考える

iOS 7 から UIAlertView - addSubView が無効になった。従来はこのメソッドを利用して UI を拡張していた (方法については前に書いたこちらの記事を参照のこと) のだけど、それはもうかなわない。というわけで代替案を検討してみる。

UIAlertView が標準で提供しているカスタマイズ機能

iOS 5 から UIAlertView は標準でカスタマイズ機能を提供している。alertViewStyle プロパティに UIAlertViewStyle 列挙体の値を指定することで UI を切り替えられる。

UIAlertViewStyle モード
UIAlertViewStyleDefault 標準のアラート。alertViewStyle プロパティの規定値。
UIAlertViewStyleSecureTextInput 単一のテキスト フィールド付きアラート。入力内容を隠してくれるので、パスワードなどに向く。App Store の認証などでも、お馴染み。
UIAlertViewStylePlainTextInput 単一のテキスト フィールド付きアラート。
UIAlertViewStyleLoginAndPasswordInput 2 段のテキスト フィールド付きアラート。ログイン時の User/Pass 入力に向く。2 段目のテキスト フィールドは入力内容を隠すタイプ。

以下はこれらを表示したところ。

UIAlertView 標準のカスタマイズ機能

こんな感じで利用する。

/**
 * アラートを表示します。
 */
- (void)showAlert
{
    UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Title"
                                                    message:@"Please enter a value"
                                                   delegate:self
                                          cancelButtonTitle:nil
                                          otherButtonTitles:@"OK", nil];
    alert.delegate       = self;
    alert.alertViewStyle = UIAlertViewStyleSecureTextInput;
    [alert show];
}

/**
 * アラート上のボタンがクリックされた時に発生します。
 *
 * @param alertView   アラート。 
 * @param buttonIndex クリックされたボタンのインデックス。
 */
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if( buttonIndex == alertView.cancelButtonIndex ) { return; }

    NSString* textValue = [alertView textFieldAtIndex:0] text];
    if( [textValue length] > 0 )
    {
        // 入力内容を利用した処理
    }
}

textFieldAtIndex にテキスト フィールドのインデックス値を指定することで内容を参照可能。インデックス値は UIAlertViewStyleSecureTextInputUIAlertViewStylePlainTextInput はテキスト フィールドが単体なので常に 0UIAlertViewStyleLoginAndPasswordInput なら Login が 0、Password は 1 となる。

テキスト入力ならこれらで十分。動作環境としても iOS 5 なら十分ではなかろうか。

進捗通知

モーダル実行される処理で時間がかかりそうなものは開始から終了までの進捗が表示されると親切。あまりに処理時間が長い場合は途中でキャンセルしたくなるかもしれない。

こうした要求へ応えるため以前は UIAlertViewUIProgressViewUIActivityIndicatorView を追加して進捗通知しつつキャンセル ボタンによる中断をサポートしていた。代替としては UIAlertView を利用するなら進捗通知は message プロパティでおこなう。更新を反映するために UIAlertView のインスタンスをクラス単位で保持して進捗にあわせて message プロパティを更新してゆくことになるだろう。

SVProgressHUD や MBProgressHUD を検討するのもよい。

これらはグラフによる進捗表示やインジケータによる待機通知、簡単なポップアップ メッセージの表示機能を提供してくれる。キャンセル ボタン相当の UI は提供されないため中断はタッチ操作をハンドリングするなどの工夫が必要。

どちらもライセンスは MIT。SVProgressHUD については使用リソースの関係で Glyphish icons についての記載があるが、そのままアプリへ組み込む分には問題ないだろう。

その他

これ以外の機能で UIAlertView をカスタマイズしていたものについては素直に UIViewContrller を利用したほうがよい。

ただしユーザーの操作するコントロールが少ないと画面として用意することがムダに感じられるかも。その場合は元の画面やアプリ全体の設定画面に統合することを検討してみる。例えば Amazon の Kindle アプリ的なタッチ操作で表示の切り替わるツールバーなどは実装も容易で使い勝手もよいと思う。

最近は画面にかぶさる形式のメニューで面白いものを見るようになった。これらも代替としてよいかもしれない。Cocoa Controls を sidebar や menu などで検索すればそういうコントロールがたくさん見つかる。有名なものだと以下になるだろうか。

どちらもライセンスは MIT。見た目と使い勝手もよい。難点があるとすれば実装がすこし大掛かりになることや初見のユーザーが戸惑いそうなことぐらいか。

まとめると

  • 通知や単純なテキスト入力なら標準の UIAlertView
  • 構成が複雑そうなら UIViewController
  • 目的やライセンスがアプリに合致するならサード パーティ製ライブラリも検討

こんな感じかな。凡庸ではあるが現実的にはこのあたりへ落ち着くのではなかろうか。