Контроллер внешнего вида для перезагрузки для обновления изменений UIAppearance

Я долго искал и не могу найти ответ. Я работаю над приложением для iOS, и у меня есть страница модальных настроек, которая появляется при нажатии кнопки и возвращается с переходом. Один из вариантов, который я хотел бы реализовать, - это настройка цветовой схемы. Я действительно хочу избегать ручного изменения цвета для каждого элемента на странице.

Apple имеет протокол UIAppearance для такого рода вещей (поэтому я могу установить цвет текста для всех кнопок и т.д. Их документация гласит:

Примечание: iOS применяет изменения внешнего вида, когда представление входит в окно, оно не меняет внешний вид представления, уже находящегося в окне. Чтобы изменить внешний вид представления, находящегося в данный момент в окне, удалите представление из иерархии представлений и затем верните его обратно.

Мой вопрос, как это сделать. Я попытался вызвать viewWillAppear и setNeedsDisplay без удачи.

Ответ 1

Попробуйте использовать этот фрагмент:

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

Ответ 2

В частности, чтобы получить текущий вид и его просмотр, попробуйте:

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

Работает для меня.

Ответ 3

Обратите внимание, что верхний ответ будет иметь негативные последствия для поведения вашей системной клавиатуры.

Оказывается, 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 для обходного пути.

Ответ 4

Для Swift:

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

Ответ 5

Для 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()
}

Ответ 6

Попробуйте

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

Ответ 7

Здесь Swift 5 с одним вкладышем:

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

Ответ 8

Для быстрой 4:

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

Ответ 9

Большинство ответов очень хороши и идеально подходят для смены языка с 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()
}