web-dev-qa-db-ja.com

キーボード上にUIAlertControllerを表示する

IOS 8以下では、キーボードが表示されたときにUIActionSheetを表示すると、キーボードの上にアクションシートが表示されます。 iOS 9では、これはもはや当てはまりません。

私のアプリにはチャット機能があり、キーボードを介してアクションを表示する必要があります。以前はUIActionSheetを使用していましたが、iOS 8までは正常に機能していました。iOS9では、アクションシートはキーボードの後ろにあります。 UIActionSheetUIAlertControllerの両方を試しました。

私たちが欲しいのはmessages.appのようなアクションシートです Action sheet in messages app.

アクションシートを独自のウィンドウに配置し、キーボードが消えたcanBecomeFirstResponderをオーバーライドしてみました。

16
rckoenes

私はこれをアプリに正確に実装しました。秘訣は、アラートコントローラーを別のウィンドウに表示することです。これはUIActionSheet実装がそれを行う方法であり、iOS 8でうまく機能しますが、9では、Appleは、キーボード実装を非常に高いウィンドウレベルのウィンドウに移動しました(10000000)。修正は、アラートウィンドウにさらに高いウィンドウレベルを与えることです(提供された定数を使用せずに、カスタムのdouble値として)。

透明度のあるカスタムウィンドウを使用する場合は、回転遷移中にウィンドウが黒くなるのを防ぐために、背景色について ここでの私の答え を必ず読んでください。

_alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
_alertWindow.rootViewController = [UIViewController new];
_alertWindow.windowLevel = 10000001;
_alertWindow.hidden = NO;
_alertWindow.tintColor = [[UIWindow valueForKey:@"keyWindow"] tintColor];

__weak __typeof(self) weakSelf = self;

UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Test" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
    weakSelf.alertWindow.hidden = YES;
    weakSelf.alertWindow = nil;
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"Test" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
    weakSelf.alertWindow.hidden = YES;
    weakSelf.alertWindow = nil;
}]];

[_alertWindow.rootViewController presentViewController:alert animated:YES completion:nil];

enter image description here

30
Leo Natan

Appleは、windowLevelを10000000より上に設定できないようになったため、Leoによって提供された答えは壊れています。修正は、カスタムUIWindowを実装し、windowLevelレシーバーをオーバーライドすることです。 :

@interface TopWindow : UIWindow @end

@implementation TopWindow
- (UIWindowLevel) windowLevel {
    return 20000000.000;
}
@end

// usage:
UIWindow* w = [[TopWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
w.rootViewController = [UIViewController new];
w.hidden = NO;

[w.rootViewController presentViewController:yourActionSheetController animated:YES completion:nil];

このアプローチには下位互換性があるはずですが、すべての既知のバージョンをテストしているわけではありません。ハッピーハッキング!

6
Emiel Mols

Leo Natanの回答に基づいて、キーボード上にアラートシートを表示するためのSwift拡張機能を作成しました。

私の簡単なテストでは、alertWindowはアラートが閉じられた後に割り当てが解除されます。これは、アラートの外部に強い参照がないためだと思います。これは、UIAlertActionsで非表示にしたり割り当てを解除したりする必要がないことを意味します。

extension UIAlertController {

    func presentOverKeyboard(animated: Bool, completion: (() -> Void)?) {

        let alertWindow = UIWindow(frame: UIScreen.mainScreen().bounds)

        // If you need a white/hidden/other status bar, use an appropriate VC.
        // You may not need a custom class, and you can just use UIViewController()
        alertWindow.rootViewController = whiteStatusBarVC()

        alertWindow.windowLevel = 10000001
        alertWindow.hidden = false

        // Set to a tint if you'd like
        alertWindow.tintColor = UIColor.greenColor()

        alertWindow.rootViewController?.presentViewController(self, animated: animated, completion: completion)
    }
}

private class whiteStatusBarVC: UIViewController {
    private override func preferredStatusBarStyle() -> UIStatusBarStyle {
        return .LightContent
    }
}
5
Kyle Bashour