UISearchController 的自定义动画?

Custom animation for UISearchController?

我正在展示 UISearchController 来自嵌入导航控制器的控制器。出现默认动画,其中搜索框从导航栏顶部下拉。

这对我来说不是一个好的用户体验,因为我会在用户点击屏幕中间的 UITextField 时显示搜索。我想做的是让 UITextField 浮动到顶部并变成搜索框,但我不知道该怎么做。

这是我的:

class PlacesSearchController: UISearchController, UISearchBarDelegate {

    convenience init(delegate: PlacesAutocompleteViewControllerDelegate) {

        let tableViewController = PlacesAutocompleteContainer(
            delegate: delegate
        )

        self.init(searchResultsController: tableViewController)

        self.searchResultsUpdater = tableViewController
        self.hidesNavigationBarDuringPresentation = false
        self.definesPresentationContext = true
        self.searchBar.placeholder = searchBarPlaceholder
    }
}

private extension ShowAddressViewController {

    @objc func streetAddressTextFieldEditingDidBegin() {
        present(placesSearchController, animated: true, completion: nil)
    }
}

我希望让文本字段飞到导航栏,而不是从顶部下拉搜索。我所追求的是与 iOS 11 文件应用程序相同的效果:

它在屏幕中间有一个文本字段,当您点击它时,它会动画到导航栏。但就我而言,文本字段在屏幕中的位置较低,最初并不是导航栏的一部分。

  1. 在 XIB 中创建一个 UIView。将其命名为 searchView。
  2. 在同一 xib 中的 UIView 上方添加 UIButton 并将其命名为 btnSearch。像下面一样 

  3. 在 ViewDidLoad 中设置搜索控制器如下:

    func setupSearchController()  {
      self.searchController = UISearchController(searchResultsController: nil)
      self.searchController.delegate = self
      self.searchController.searchBar.delegate = self
      definesPresentationContext = true
      self.searchController.dimsBackgroundDuringPresentation = false
      self.searchController.searchBar.sizeToFit()
      searchView.addSubview(self.searchController.searchBar)
      self.searchController.searchBar.isHidden = true
      self.searchController.searchBar.tintColor = UIColor.white
      self.searchController.searchBar.showsCancelButton = false
      UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).tintColor = session?.makeColor(fromHexString: TYPE_COLOR, alpha: 1.0)
      self.searchController.searchBar.isTranslucent = false
      self.searchController.searchBar.barTintColor = UIColor(red: 239.0 / 255.0, green: 135.0 / 255.0, blue: 1.0 / 255.0, alpha: 1.0)
    }
    

    此方法将在搜索视图中以编程方式设置搜索控制器。

  4. 现在您只需以编程方式显示 searchcontroller。在步骤 2 中添加按钮的单击方法。在方法名称下方调用此方法名称 showsearchAnimation:

    func ShowSeachAnimation() {
      searchFrame = searchView.frame (add one global variable "searchFrame" in controller which saves searchView.frame so it will be used when cancel button clicked on search)
      self.btnSearch.isHidden = true        
      var yAxis : CGFloat = 20
      if #available(iOS 11 , *) {
         yAxis = 8
      } else  {
         yAxis = 20
      }
      searchView.translatesAutoresizingMaskIntoConstraints = true
      searchView.frame = CGRect(x: 0, y: yAxis, width: view.frame.size.width, height: view.frame.size.height - yAxis)
    
      self.searchController.searchBar.isHidden = false
      self.searchController.searchBar.becomeFirstResponder()
      self.searchController.searchBar.showsCancelButton = true
      self.searchBar(self.searchController.searchBar, textDidChange: "")
      searchView.layoutIfNeeded()
    }
    
  5. 为了隐藏搜索栏,在搜索控制器委托中添加名为"searchbarcancelbuttonclicked"的搜索隐藏方法:

    func searchViewHideAnimation()  {
      self.removeNavigationBar()
      self.navigationController?.isNavigationBarHidden = false
      self.searchController.searchBar.text = " "
      self.searchController.searchBar.isHidden = true
      UIView.animate(withDuration: 0.3, animations: {() -> Void in
          self.searchView.frame = self.searchFrame!
          self.btnSearch.isHidden = false
      }, completion: {(_ finished: Bool) -> Void in
          self.searchView.layoutIfNeeded()
      })
    }
    

UISearchController

UISearchController 是一个很难自定义的组件。根据我的经验,我可以说,最好按原样使用它,不要进行任何激烈或重要的定制。否则,自定义可能会导致代码混乱、全局状态变量、UIView 层次结构的运行时技巧等。 如果仍然需要特定行为,最好从头开始实现搜索控制器或​​使用第三方控制器。

默认实现

看起来 UISearchController 旨在与 table header 视图中安装的 UITableView 和 UISearchBar 结合使用。甚至苹果官方代码示例和文档也提供了这样的用法示例(参见UISearchController)。尝试在其他地方安装 UISearchBar 通常会导致许多丑陋的副作用,包括搜索栏框架、位置、抽动动画、方向变化等。

从 iOS 11 开始,UINavigationItem 得到 searchController 属性。它允许将搜索控制器集成到您的导航界面中,因此搜索看起来就像 iOS 文件或 iOS AppStore 应用程序。 UISearchController 的行为仍然与另一个组件耦合,但我相信它比一直与 UITableView 耦合更好。

可能的解决方案

在我看来,您的问题有多种可能的解决方案。我将按照需要实现的工作量增加的顺序提供它们:

  1. 如果您仍想使用 UISearchController,请考虑按原样使用它,不要进行重大自定义。 Apple 提供示例代码,演示如何使用 UISearchController(参见 Table Search with UISearchController)。
  2. 有几个第三方库可能更灵活,具有许多附加功能。例如:YNSearch, PYSearch。请看一下。
  3. 随着 UISearchController 的呈现,您可以尝试将 alpha 从 1 更改为 0 来向上移动 UITextField。这会让人感觉 UITextField 正在平滑地转换为 UISearchBar。 Chris Slowik 提供的文章中描述了这种方法(请参阅对原始 post 的评论)。我唯一要改进的是使用过渡协调器的动画(参见示例 here),它将使同步时间的动画更流畅。最终实施也将更加清晰。
  4. 作为一种选择,您可以尝试仅使用 UISearchBar 或什至普通的 UITextField 来设计您自己的搜索控制器。
  5. 您可以子类化 UISearchController 并添加 UITextField object。 UISearchController 符合 UIViewControllerAnimatedTransitioning 和 UIViewControllerTransitioningDelegate 协议,其中 UITextFiled 可以与过渡动画一起删除或添加。

希望对您有所帮助。

更新:

我已经实施了我在第 3 点中描述的方法。这是它的工作原理:

您可以找到代码片段 here。请注意,这只是代码示例,可能存在未处理的情况。然后检查两次。

您可以尝试使用我的 https://github.com/Blackjacx/SHSearchBar,它基本上就是您的文本字段。您可以在文本字段编辑开始时向左侧、右侧和顶部添加约束并调整顶部约束。同时,您可以使用覆盖视图隐藏动画导航栏并使背景变灰。这样你就可以最大限度地控制你的动画,而且这个方法并不像听起来那么困难。