草庐IT

关于ios:Force view controller to reload to refresh UIAppearance changes

codeneng 2023-03-28 原文

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,我会使用此代码。

有关关于ios:Force view controller to reload to refresh UIAppearance changes的更多相关文章

  1. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  2. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  3. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  4. ruby - 为什么不能使用类IO的实例方法noecho? - 2

    print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

  5. ruby-on-rails - 关于 Ruby 的一般问题 - 2

    我在我的rails应用程序中安装了来自github.com的acts_as_versioned插件,但有一段代码我不完全理解,我希望有人能帮我解决这个问题class_eval我知道block内的方法(或任何它是什么)被定义为类内的实例方法,但我在插件的任何地方都找不到定义为常量的CLASS_METHODS,而且我也不确定是什么here,并且有问题的代码从lib/acts_as_versioned.rb的第199行开始。如果有人愿意告诉我这里的内幕,我将不胜感激。谢谢-C 最佳答案 这是一个异端。http://en.wikipedia

  6. ruby - 我怎样才能更好地了解/了解更多关于 Ruby 的知识? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我最近开始学习Ruby,这是我的第一门编程语言。我对语法感到满意,并且我已经完成了许多只教授相同基础知识的教程。我已经写了一些小程序(包括我自己的数组排序方法,在有人告诉我谷歌“冒泡排序”之前我认为它非常聪明),但我觉得我需要尝试更大更难的东西来理解更多关于Ruby.关于如何执行此操作的任何想法?

  7. ruby - 关于 Ruby 中 Dir[] 和 File.join() 的混淆 - 2

    我在Ruby中遇到了一个关于Dir[]和File.join()的简单程序,blobs_dir='/path/to/dir'Dir[File.join(blobs_dir,"**","*")].eachdo|file|FileUtils.rm_rf(file)ifFile.symlink?(file)我有两个困惑:首先,File.join(@blobs_dir,"**","*")中的第二个和第三个参数是什么意思?其次,Dir[]在Ruby中有什么用?我只知道它等价于Dir.glob(),但是,我对Dir.glob()确实不是很清楚。 最佳答案

  8. elasticsearch源码关于TransportSearchAction【阶段三】 - 2

    1.回顾.TransportServicepublicclassTransportServiceextendsAbstractLifecycleComponentTransportService:方法:1publicfinalTextendsTransportResponse>voidsendRequest(finalTransport.Connectionconnection,finalStringaction,finalTransportRequestrequest,finalTransportRequestOptionsoptions,TransportResponseHandlerT>

  9. 关于Qt程序打包后运行库依赖的常见问题分析及解决方法 - 2

    目录一.大致如下常见问题:(1)找不到程序所依赖的Qt库version`Qt_5'notfound(requiredby(2)CouldnotLoadtheQtplatformplugin"xcb"in""eventhoughitwasfound(3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentationfault,或者Illegalinstruction(coredumped)非法指令(4)ldd应用程序或者库,查看运行所依赖的库时,直接报段错误二.问题逐个分析,得出解决方法:(1)找不到程序所依赖的Qt库version`Qt_5'

  10. ruby - 为 IO::popen 拯救 "command not found" - 2

    当我将IO::popen与不存在的命令一起使用时,我在屏幕上打印了一条错误消息:irb>IO.popen"fakefake"#=>#irb>(irb):1:commandnotfound:fakefake有什么方法可以捕获此错误,以便我可以在脚本中进行检查? 最佳答案 是:升级到ruby​​1.9。如果您在1.9中运行它,则会引发Errno::ENOENT,您将能够拯救它。(编辑)这是在1.8中的一种hackish方式:error=IO.pipe$stderr.reopenerror[1]pipe=IO.popen'qwe'#

随机推荐