web-dev-qa-db-ja.com

ビューコントローラを強制的にリロードして、UIAppearanceの変更を更新します

私はかなり長い間探していましたが、答えが見つかりません。私はiOSアプリで作業しており、ボタンをタップすると表示され、セグエで戻るモーダル設定ページがあります。実装したいオプションの1つは、配色の設定です。ページ上のすべての要素の色を手動で変更することは本当に避けたいです。

Appleには、この種のことのための IAppearance プロトコルがあります(したがって、すべてのボタンのテキストの色などを設定できます。

注:iOSは、ビューがウィンドウに入るときに外観の変更を適用しますが、すでにウィンドウにあるビューの外観は変更しません。現在ウィンドウにあるビューの外観を変更するには、ビュー階層からビューを削除してから元に戻します。

私の質問はこれをどのように行うかです。運が悪かったので、viewWillAppearとsetNeedsDisplayを呼び出してみました。

19
The Lone Fellow

このスニペットを使用してみてください:

NSArray *windows = [UIApplication sharedApplication].windows;
for (UIWindow *window in windows) {
    for (UIView *view in window.subviews) {
        [view removeFromSuperview];
        [window addSubview:view];
    }
}

http://snipplr.com/view/75259/refresh-uiappearance-after-application-loaded/

UIAppearanceを使用してアプリのテーマを変更した後、それは私にとって完璧に機能します

21

具体的には、現在のビューとそのスーパービューを取得するには、次のことを試してください。

UIView *currentview = self.window.rootViewController.view;
UIView *superview = currentview.superview;
[currentview removeFromSuperview];
[superview addSubview:currentview];

私のために働きます。

8
Adrian

一番上の答えは、システムのキーボードの動作に悪影響を与えることに注意してください。

IOSは、キーボードが表示されるたびに、内部にUITextEffectsWindowクラスを持つ新しいシステムウィンドウを作成することがわかりました。取り外すと、キーボードの動作に悪影響を与える可能性があります。たとえば、入力アクセサリビューはキーボードから切り離され、ナビゲーションコントローラの短い点滅を除いて表示されません。

次のような追加のチェックを使用して、この問題を回避できます。

for window in UIApplication.shared.windows {
    // Whenever a system keyboard is shown, a special internal window is created in application
    // window list of type UITextEffectsWindow. This kind of window cannot be safely removed without
    // having an adverse effect on keyboard behavior. For example, an input accessory view is
    // disconnected from the keyboard. Therefore, a check for this class is needed. In case this class
    // that is indernal is removed from the iOS SDK in future, there is a "fallback" class check on
    // NSString class that always fails.
    if !window.isKind(of: NSClassFromString("UITextEffectsWindow") ?? NSString.classForCoder()) {
        window.subviews.forEach {
            $0.removeFromSuperview()
            window.addSubview($0)
        }
    }
}

UITextEffectsWindowは内部的なものであり、将来変更される可能性があることに注意してください。これが、!を使用して変数をアンラップせず、代わりにフォールバックの負のNSStringクラスを提供する理由です(ウィンドウのタイプはNSStringクラスではありません)。

注:単純なアプリの場合、回避策としてUIApplication.shared.keyWindowを使用して生きることができます。

7
Petr Dvořák

Swiftの場合:

let windows = UIApplication.sharedApplication().windows
for window in windows {
    for view in window.subviews {
        view.removeFromSuperview()
        window.addSubview(view)
    }
}
6
Daniel Tovesson

Swift 3.0.2:

for window in UIApplication.shared.windows {
    for view in window.subviews {
        view.removeFromSuperview()
        window.addSubview(view)
    }
    // update the status bar if you change the appearance of it.
    window.rootViewController?.setNeedsStatusBarAppearanceUpdate()
}
5
Bjarte

これがSwift 5ワンライナーです:

UIApplication.shared.windows.forEach { $0.subviews.forEach { $0.removeFromSuperview(); self.window?.addSubview($0) }}
2
JanApotheker

試してみてください

[self.yourView removeFromSuperView];
[self addSubView:yourView];
2
Milo

Swift 4:

let windows = UIApplication.shared.windows
for window in windows {
    for view in window.subviews {
        view.removeFromSuperview()
        window.addSubview(view)
    }
}
1
ironRoei

ほとんどの答えは非常に良く、言語を[〜#〜] ltr [〜#〜]から[〜#〜] rtl [〜#〜]に変更するのに最適ですが時々タブバーナビゲーションタイトルおよびナビゲーションバータイトルは翻訳されません。次のコードで問題を修正しました

if let app = UIApplication.shared.delegate as? AppDelegate, let window = app.window {
    window.rootViewController = TabNavigationController()
    let tab = window.rootViewController as? UITabBarController
    tab?.selectedIndex = 3
    window.makeKeyAndVisible()
}
0
Kosrat D. Ahmad