自定义 UISearchController 动画

Posted

技术标签:

【中文标题】自定义 UISearchController 动画【英文标题】:Custom UISearchController Animation 【发布时间】:2015-02-01 19:56:03 【问题描述】:

底线问题:

如何覆盖关闭属于 UISearchController 的 searchBar 的默认动画?


标准搜索控制器行为:

好的,所以我正在尝试创建一个自定义动画,用于当附加到 UISearchController 的 UISearchBar 变为活动状态时。似乎标准动画期望 searchBar 以占据屏幕的宽度开始。当动画开始时,它会缩小 searchBar 并淡入它右侧的取消按钮。

我想要实现的目标:

我想让我的 searchBar 以较小的状态开始,大约是屏幕宽度的一半,以便在它旁边的导航栏中也可以放置两个按钮。

当前动画:

当 searchBar 变为活动状态时,我希望动画展开 searchBar 并让取消按钮淡入。

关闭动画:

当搜索栏被关闭时,我希望发生完全相反的动画:取消按钮淡出,搜索栏缩小到原来的大小。


问题:

我找到了一种通过使用 UISearchControllerDelegate 方法 presentSearchController 来实现所需呈现动画的方法:

func presentSearchController(searchController: UISearchController) 

    // Animate Buttons
    UIView.animateWithDuration(0.1, animations: 

        // First Hide Buttons
        self.createMoxyButton.alpha = 0
        self.centerMapButton.alpha  = 0
    )

    // Animate Search Bar
    UIView.animateWithDuration(0.5, animations: 

        // Search Bar
        searchController.searchBar.frame = CGRectMake(searchController.searchBar.frame.origin.x, searchController.searchBar.frame.origin.y, self.wBounds - 40, searchController.searchBar.frame.height)
        self

    )


但我无法实现解雇动画。我曾尝试使用 didDismissSearchController: 和 willDismissSearchController: 委托方法,但它会导致奇怪的行为,并且不使用我在这些各自的委托方法中设置的帧动画。当 searchBar 被关闭时,它将扩展到全屏宽度,同时淡出取消按钮,然后它会立即将 searchBar 的框架更改回原始大小,忽略我的动画。我也尝试使用 removeAllAnimation() 方法尝试阻止默认动画的发生,但无济于事。

func didDismissSearchController(searchController: UISearchController) 
    searchController.searchBar.layer.removeAllAnimations()

    // Animate
    UIView.animateWithDuration(0.5, animations: 

        // Show hidden buttons
        self.createMoxyButton.alpha = 1
        self.centerMapButton.alpha  = 1

        // Search Bar
        searchController.searchBar.frame = CGRectMake(searchController.searchBar.frame.origin.x, searchController.searchBar.frame.origin.y, self.wBounds - 10 - self.createMoxyButton.frame.size.width - 20 - self.centerMapButton.frame.size.width - 20, searchController.searchBar.frame.height)
        self

    )

关闭搜索栏的问题图片

Gif 动画开始时 searchBar 处于 Active 状态,并且取消按钮可见

【问题讨论】:

这个有运气吗?我也卡在这里了。 @CliffW 不,没有运气尝试直接使用 UICSearchController。我尝试了很多尝试,但都失败了。我最终使用了一个易于制作动画的 UISearchBar 本身,然后我不得不手动对 UISearchController 提供的所有方法进行硬编码,以实现所需的效果和功能。可悲的是,我们最终从项目中删除了这个搜索栏并选择了不同的布局......我将不得不在我的仓库中挖掘代码,我会尽快在此处发布作为答案。 【参考方案1】:

子类 UISearchController 并实现可选的UIViewControllerTransitioningDelegate 方法 - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;

返回您的动画对象以执行关闭动画。

【讨论】:

【参考方案2】:

我不能声称这会产生超级流畅的动画,但它看起来并不可怕并且可能会有所帮助(甚至是您所需要的)。如果您想尝试一下,您可以创建一个新项目(单视图应用程序)并将导航控制器添加为初始控制器,并将 ViewController 类的对象作为其根控制器(只是为了快速获取导航栏)。下面的代码是我对ViewController的整个实现

import UIKit

class ViewController: UIViewController,UISearchBarDelegate,UISearchControllerDelegate,UISearchResultsUpdating 

    lazy var createMoxyButton:UIBarButtonItem = 
        //customize this as your equire
        let button = UIBarButtonItem(title: "Done", style: .Plain, target: nil, action: nil)
        return button
    ()

    lazy var centerMapButton:UIBarButtonItem = 
        //customize this as your equire
        let button = UIBarButtonItem(title: "Done", style: .Plain, target: nil, action: nil)
        return button
        ()

    lazy var searchController:UISearchController = 
        let controller = UISearchController(searchResultsController: self)
        controller.delegate = self
        controller.searchResultsUpdater = self
        controller.dimsBackgroundDuringPresentation = false
        controller.hidesNavigationBarDuringPresentation = false
        return controller
    ()

    override func viewDidLoad() 
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.navigationItem.titleView = self.searchController.searchBar
        self.navigationItem.rightBarButtonItems = [self.centerMapButton,self.createMoxyButton]
        self.edgesForExtendedLayout = UIRectEdge.None
        self.searchController.searchBar.delegate = self
    

    func updateSearchResultsForSearchController(searchController: UISearchController) 

    

    func searchBarTextDidBeginEditing(searchBar: UISearchBar) 
        //this needs to be done because in shouldEndEditing
        //we need to set it to false to smooth animation
        searchBar.showsCancelButton = true
        self.navigationItem.setRightBarButtonItems(nil, animated: true)
    

    func searchBarShouldEndEditing(searchBar: UISearchBar) -> Bool 
        searchBar.showsCancelButton = false
        self.navigationItem.rightBarButtonItems = [self.centerMapButton,self.createMoxyButton]
        return true
    

【讨论】:

以上是关于自定义 UISearchController 动画的主要内容,如果未能解决你的问题,请参考以下文章

如何在 UISearchController 中使用自定义视图控制器获取结果?

UISearchController 作为 UITableViewHeader

UISearchController 与单元格布局混淆

在导航推送上激活没有动画的 UISearchController

UISearchController 滑动时错误的动画然后消失

如何在没有动画的情况下将 UISearchController 设置为活动?