【问题标题】:Subviews in presented ViewController gets wrong position after rotation呈现的 ViewController 中的子视图在旋转后位置错误
【发布时间】:2019-10-22 22:38:50
【问题描述】:

我正在尝试使用UISearchController,但我做不到。我呈现一个干净的UISearchController 来自我自己的UIViewController,它看起来很棒 - 但只要我旋转设备,它就会向上或向下移动几个点。

要重新创建它,只需执行以下几个步骤:

  1. 创建一个新的单一视图项目
  2. 从项目文件中删除Main.storyboard从项目设置中删除其名称(项目 -> 常规 -> 目标 -> 主界面)

AppDelegate.swift:

application didFinishLaunchingWithOptions...{
    window = UIWindow(frame: UIScreen.main.bounds)
    window?.rootViewController = ViewController()
    window?.makeKeyAndVisible()
    return true
}

ViewController.swift:

class ViewController: UIViewController{
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = .white
        let button = UIButton(frame: CGRect(x: 20, y: 200, width: 100, height: 40))
        button.setTitle("Search", for: .normal)
        button.backgroundColor = .black
        button.addTarget(self, action: #selector(click), for: .touchUpInside)
        self.view.addSubview(button)
    }
    @objc func click(){
        self.present(UISearchController(searchResultsController: nil), animated: true, completion: nil)
    }
}

就是这样。这就是我所看到的:

在设备处于纵向模式时显示搜索在纵向上看起来很棒 - 但如果您在显示搜索栏时将设备旋转到横向,它将被错误地定位,在屏幕顶部上方几个像素处。

在横向显示搜索将产生相反的结果。它在横向看起来很棒,但是当它旋转到纵向时,整个搜索控制器视图将被向下推几个像素。

这不是栏杆高度大小的问题。整个条被向上/向下推。

我尝试进一步调查。我将搜索控制器从横向模式呈现并旋转为纵向,然后调试视图层次结构:

说实话,我不太确定我在看什么。最顶层的视图是嵌入在_UISearchBarContainerView 中的UISearchBarBackground,而_UISearchControllerView 则位于_UISearchControllerView 中。

正如您在右侧的尺寸检查器中看到的,中间视图“容器”具有y: 5,这没有任何意义。调试正确状态时,y 为 0。真正有趣的是,在这种损坏情况下,最顶层的视图有 y: -44,正确时也有相同的 - 但你可以清楚地看到上面还有一些空间它。似乎存在三个不同的 y 位置。没看懂。

我已经阅读了一些关于如何实现UISearchController 的指南,但实际上我发现的每个示例都是人们以模态方式呈现包含 SearchController 的自定义 ViewController。这将导致整个自定义 ViewController 从下方动画化。

由于UISearchControllerUIViewController 的子类,我想测试一下直接呈现它,而不是作为常规UIViewController 的一部分。这给出了很酷的效果,即 searchBar 从上方动画,键盘从下方动画。

但是为什么这不起作用呢?

编辑:我刚刚发现如果我在项目设置中启用Hide status barUISearchController 在横向上看起来比上面的“正确状态”更正确,甚至动画正确的肖像。这很奇怪,因为状态栏根本没有改变。它在风景中从未可见。为什么会这样?好像太坑了看看这三种状态:

第一种状态是从纵向显示搜索控制器然后旋转到横向(不管Hide status bar是否启用。

第二种状态是当Hide status bar 为假时从横向显示搜索控制器

第三种状态是当Hide status bar 为真时从横向显示搜索控制器。

【问题讨论】:

    标签: ios swift uiviewcontroller uikit uisearchcontroller


    【解决方案1】:

    你可以做到这一点

    class ViewController: UIViewController {
    
    let sc = UISearchController(searchResultsController: nil)
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        self.view.backgroundColor = .white
        let button = UIButton(frame: CGRect(x: 20, y: 200, width: 100, height: 40))
        button.setTitle("Search", for: .normal)
        button.backgroundColor = .black
        button.addTarget(self, action: #selector(click), for: .touchUpInside)
        self.view.addSubview(button)
    
    
    }
    
    @objc func click(){
        self.present(sc, animated: true, completion: nil)
    }
    
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    
        var mFrame = sc.view.frame
        mFrame.origin.y = 5.0
        sc.view.frame = mFrame
    }
    

    【讨论】:

    • 这不是正确的解决方案。它会在纵向模式下甚至在设备上方添加额外的空间。
    【解决方案2】:

    documentation中所述:

    虽然 UISearchController 对象是一个视图控制器,但你应该 永远不要直接从您的界面呈现它。如果你想呈现 明确的搜索结果界面,包装你的搜索控制器 在 UISearchContainerViewController 对象中并呈现该对象 而是。

    尝试将您的 UISearchController 包装在 UISearchContainerViewController 中。

    【讨论】:

    • 有趣!我需要学习如何阅读。但这并不完全有效。如果我更改self.present(UISearchContainerViewController(searchController:UISearchController:searchResultsController:nil)),我只会得到一个带有隐形搜索栏的黑屏。这是否意味着self 可能必须是 UISearchContainerViewController?.. 我必须测试一些东西.. 这似乎也没有使用上面的漂亮动画..
    • 实际上,UISearchContainerViewController 的文档是这样说的:尽管您可以模态地呈现搜索控制器对象,但您永远不应该将其压入导航控制器的堆栈或将其用作另一个容器视图控制器。相反,嵌入这个类的一个实例,让它管理搜索控制器内容的呈现。 虽然你可以以模态方式呈现一个搜索控制器对象 - 这不正是我的样子想做什么?我觉得您找到的文档更针对 self.addChild(sc),我不是
    • 例如,我将它推送到导航堆栈上,并且我没有将它用作任何东西的子级。我只是想以模态方式呈现它。
    【解决方案3】:

    如何让自定义视图包含搜索栏。 让它在图层的顶部。

    当发生旋转时,更新它的框架/约束。

    【讨论】:

      【解决方案4】:

      这在 iPhone X 的设计指南中有介绍。现在导航栏包含搜索控制器。您可以实例化搜索控制器并将其设置为 navigationItem.searchController。现在它将在旋转时处理搜索控制器。

      var search = UISearchController(searchResultsController: nil)
      self.navigationItem.searchController = search
      

      【讨论】:

      • 我知道,但这不是我想要达到的目标。我的 ViewController 没有导航栏(即没有导航项),但它需要以模态方式显示搜索控制器。为了解决这个问题,我必须在 UINavigationController 中创建一个 ViewController,然后设置它的 navigationItem。正如我所提到的,每个人都是这样做的。结果将是一个完整的 UIViewController 从下面动画。根据文档,以及 UISearchController 接受 searchResultsController 的事实,应该可以在没有 NavigationController 的情况下呈现它。
      • 正如您在我的示例代码中看到的那样,没有使用单个 UINavigationController,但它仍然以“正确”的方式呈现。它似乎以某种形式呈现在一个栏中,我认为这是呈现它的一种预期方式(在 NavCon 之外)。我想保留那个精美的动画,搜索栏从上面下来,键盘从下面下来。甚至是透明背景,这样当没有任何结果时我可以看到原始的 ViewController,然后点击以将其全部关闭。
      猜你喜欢
      • 2018-06-15
      • 1970-01-01
      • 2013-11-11
      • 2011-02-27
      • 2015-04-11
      • 1970-01-01
      • 2014-12-16
      • 1970-01-01
      • 2013-08-11
      相关资源
      最近更新 更多