[iOS] AlertやModalを閉じるときに上に重ねてインジケーターを表示したい

2017/05/12

こんにちは。きんくまです。
今回は参考ページの紹介です。

私はフォルメモというメモ帳アプリを開発しています。
最近ようやく半年ぶりくらいにアップデートの作業を進めています。
>> フォルメモ – フォルダつきメモ帳、日記

現在ストアに出ているバージョンだとDBの操作をしていると更新するデータが多かったりする場合、処理が重いため画面が止まってしまいます。非常にユーザー体験的にマズいです、、。

あと、いろいろとメモやフォルダの移動や削除を行うときの動作があやしかったりして、プログラムを全体的に見直して修正しています。おかげで、だいぶ良くなってきました。(結構大変だった、、)

それで、さきほどの処理が重くて画面が止まってしまうときの対策として、DBの操作はメインスレッドとは別スレッドで行い、その間メインスレッドはローディングのくるくるを表示させるというのがあります。
こんな感じ。

progress_hud

くるくるをモーダルで出そうとしたが、、

このくるくるみたいなやつは、ProgressHUDみたいな名前のライブラリでたくさんgithubにあがっています。ただ今回は、くるくる画像を前面に出すだけなので、これぐらいだったら自分で作ってみようと思いました。

それで、出したり消したりする仕組みはできたのですが、困ったのが表示させるところ。
最初はモーダルで出してみようとしました。

一番前面のViewControllerから出せばよさそうなのですが、一番前面のViewControllerがモーダルだったり、アラートだったりすると、それらからローディング画面を出したと同時に、それらを閉じる場合にうまくいきませんでした。

モーダルの上にモーダルを重ねることはできるのですが、一番上のモーダルを出す瞬間に、ひとつ後ろのモーダルが閉じてしまうためにおかしくなるというか。

ちなみに一番上のViewControllerの取り方を調べたところ、こうなりました。

var topViewController:UIViewController? = self
while(topViewController?.presentedViewController != nil){
    topViewController = topViewController?.presentedViewController
}

UIWindowで解決

で、結局結論としては、UIWindowをもうひとつ新しく作って、それにくるくるを表示させることで解決しました。

>> [iOS] UIWindowを追加する
>> [iOS] 複数のUIWindowの挙動を確認する
>> iOS開発におけるウィンドウ「UIWindow」の知られざる活用方法とは? #iOS

ProgressViewControllerというstoryboardつきのViewControllerを作ってそこにくるくるを配置しました。
ProgressHUDControllerを新規作成してメインのViewControllerでインスタンス化。
見せるイベントがきたらshow()して、閉じるイベントがきたらhide()する感じです。

UIWindowを新しく作って他のWindowから切り離されているため、他のWindowがアラートだろうとモーダルだろうと関係なく動きました。

class ProgressHUDController {
    var progressWindow:UIWindow?
    var progressViewController:ProgressViewController?
    
    init(){
        
    }
    
    func show(){
        //すでに見せていたら何もしない
        if progressWindow != nil {
            return
        }
        
        progressWindow = UIWindow(frame: UIScreen.main.bounds)
        
        let storyboard:UIStoryboard = UIStoryboard(name: "ProgressViewController", bundle: nil)
        progressViewController = storyboard.instantiateInitialViewController() as? ProgressViewController
        if progressViewController == nil {
            return
        }
        
        progressWindow?.rootViewController = progressViewController
        progressWindow?.backgroundColor = UIColor.clear
        progressWindow?.windowLevel = UIWindowLevelAlert + 100
        progressWindow?.makeKeyAndVisible()
    }
    
    func hide(){
        progressViewController?.view.removeFromSuperview()
        progressWindow?.rootViewController = nil
        progressWindow = nil
        
        UIApplication.shared.delegate?.window??.makeKeyAndVisible()
    }
}

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る