Force view controller to reload to refresh UIAppearance changes
我已经搜索了很长时间,但找不到答案。我正在开发一个 iOS 应用程序,并且有一个模式设置页面,该页面出现在点击一个按钮并返回一个 segue。
我想实现的选项之一是配色方案设置。我真的想避免手动更改页面上每个元素的颜色。
Apple 为这类事情提供了 UIAppearance 协议(因此我可以设置所有按钮的文本颜色等。
他们的文档说:
Note: iOS applies appearance changes when a view enters a window, it doesn’t change the appearance of a view that’s already in a window. To change the appearance of a view that’s currently in a window, remove the view from the view hierarchy and then put it back.
我的问题是如何做到这一点。我试过调用 viewWillAppear 和 setNeedsDisplay 没有运气。
- 从视图层次结构中删除视图 – 唯一的方法是 [view removeFromSuperView] 或者如果视图被推送,那么您可以弹出视图并再次推送它而不使用动画
尝试使用这个片段:
1
2 3 4 5 6 7 |
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 更改应用程序主题后,它对我来说非常适合
- 这也适用于我,但看起来真的像一个”破解坚果的大锤”解决方案。我认为我最好避免 UIAppearance 如果这是它所需要的 – 我的使用会比偶尔的主题更改更频繁一些。
- 是的,如果没有更改/偶尔 UI 更改,则 UIAppearance。如果您需要频繁更新 UI,则需要编写自己的主题代码。
- 工作!内存效率高吗?
- 这不是最好的,也不是最差的。但我没有找到另一种方法来实现它
请注意,上面的答案会对您的系统键盘行为产生不利影响。
事实证明,每当显示键盘时,iOS 都会在后台创建一个带有 UITextEffectsWindow 类的新系统窗口。如果您删除它,您的键盘行为可能会受到负面影响。例如,输入附件视图将与键盘分离并且不可见,除了导航控制器中的短暂闪烁。
您可以通过使用附加检查来解决此问题,如下所示:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 |
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 作为解决方法。
- 感谢您发布此信息。可能永远不会弄清楚为什么我的 UIToolbar 在主题更改后从键盘上消失了。
- 我认为 UIApplication.shared.keyWindow 应该是主要答案,因为大多数应用程序应该只包含一个窗口。为什么有人会在 iOS 应用程序中创建额外的窗口?废话。
- @m8labs 您无需创建额外的窗口——只要在 UI 中显示键盘,iOS 就会自动为您创建第二个窗口。这是您在操作 UI 层次结构时需要了解的 iOS 操作系统的实现技术。
具体来说,要获取当前视图及其父视图,请尝试:
1
2 3 4 |
UIView *currentview = self.window.rootViewController.view;
UIView *superview = currentview.superview; [currentview removeFromSuperview]; [superview addSubview:currentview]; |
为我工作。
对于斯威夫特:
1
2 3 4 5 6 7 |
let windows = UIApplication.sharedApplication().windows
for window in windows { for view in window.subviews { view.removeFromSuperview() window.addSubview(view) } } |
对于 Swift 3.0.2:
1
2 3 4 5 6 7 8 |
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() } |
这是一个 Swift 5 单线:
1
|
UIApplication.shared.windows.forEach { $0.subviews.forEach { $0.removeFromSuperview(); self.window?.addSubview($0) }}
|
- 它工作正常,但会影响键盘行为(打开键盘时崩溃),我建议看下面的答案,它适用于所有场景
试试
1
2 |
[self.yourView removeFromSuperView];
[self addSubView:yourView]; |
- 谢谢。如果我想从我的视图控制器类中执行此操作,我应该在什么上调用 addSubView? self 下没有同名的方法,我无法将其添加回 self.view。
对于 swift 4:
1
2 3 4 5 6 7 |
let windows = UIApplication.shared.windows
for window in windows { for view in window.subviews { view.removeFromSuperview() window.addSubview(view) } } |
- 出于某种原因,这不适合我。我必须再次调用:UINavigationBar.appearance().titleTextAttributes = … 和 UIBarButtonItem.appearance().setTitleTextAttributes(…, for: .normal) – 令人惊讶的是,只有导航栏标题外观发生变化,而不是栏按钮项?!他们保持不变?这是在 iOS 11 上
- @AhmedKhedr,是的,但我认为这不是你的问题。我认为问题在于您的外观配置。您可以显示您的代码,我会看一下,这是我的示例: UILabel.appearance(whenContainedInInstancesOf: [UITableViewCell.self]).textColor = .white let windows = UIApplication.shared.windows for window in windows { for在 window.subviews { view.removeFromSuperview() window.addSubview(view) } } 中查看
- 这里… gist.github.com/aakhedr/a485e008ee2202ae741bb5cfddb77674
- @AhmedKhedr 我的代码在其中的机器人中运行良好。尝试将 func appearances() 放在 func setupProxies() 中,看看它是否正常工作
- UIBarButtonItems 包括后退按钮需要重置,否则它们只会在下一个绘图周期中重绘 – 这是在 iOS11 中
- UISegmentedControls 也一样——显然任何超类是 UIBarItem 的东西——为什么?不知道!也许其他人可以解释…
- @AhmedKhedr 在让 windows = UIApplication.shared.windows 之前调用 setupProxies()。
- @AhmedKhedr 你想给我看完整的代码吗?
- 这是要点 – 这就是全部
- @AhmedKhedr 无法使用此代码…这是什么字体?
- 这是 GitHub github.com/aakhedr/BarButtonItem 上示例项目的链接
- @AhmedKhedr 和 IronRoei 我也有同样的问题,有更新吗??
- @KosratD.Ahmad 什么都没有…甚至 Apple 错误报告和技术支持也没有对此问题作出回应…
- 谢谢@AhmedKhedr,我刚刚通过重新签名根控制器视图来解决===> if let app = UIApplication.shared.delegate as? AppDelegate,让 window = app.window { window.rootViewController = TabNavigationController() 让 tab = window.rootViewController 作为? UITabBarController tab?.selectedIndex = 3 window.makeKeyAndVisible() }
大多数答案非常适合将语言从 LTR 更改为 RTL,但有时标签栏导航标题和导航栏标题不会被翻译。我用以下代码
解决了这个问题
1
2 3 4 5 6 |
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() } |
objective C
self.view.window.overrideUserInterfaceStyle = UIUserInterfaceStyleDark;
如果我想在所有视图控制器中更改 overrideUserInterfaceStyle,我会使用此代码
- 嗨:),您能否添加更多解释以支持您的回答。谢谢。
- 你好!当然。如果我想在所有视图控制器中更改 overrideUserInterfaceStyle,我会使用此代码。
来源:https://www.codenong.com/20875107/