使用 UISearchController 同时为 UISearchBar 和 UIBarButtonItem 设置动画

Animate UISearchBar and UIBarButtonItem simultaneously with UISearchController

我正在尝试重现类似于地图应用程序之一的搜索界面。

我在 navigationBar 中使用 UISearchController 及其 searchBar。我在那个导航栏上也有一个 rightBarButtonItem

默认情况下,当显示搜索控制器时,搜索栏的取消按钮显示在现有的右侧项目旁边。我想做的——就像地图应用程序一样——是在显示 searchController 时隐藏我的右侧导航项,并在它被关闭时再次显示它。

我已经设法使用委托方法做到了,但是动画中有一个非常难看的跳跃,我想知道如何避免这种情况。

这是我的代码(右边的栏项将切换慢速动画,使错误更容易看到)

AppDelegate.h

//
//  AppDelegate.h
//  SearchNavigationItemAnimation
//

#import <UIKit/UIKit.h>


@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end

AppDelegate.m

//
//  AppDelegate.m
//  SearchNavigationItemAnimation
//

#import "AppDelegate.h"
#import "SearchViewController.h"

@interface AppDelegate ()
@end


@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

    SearchViewController *rootController = [[SearchViewController alloc] init];
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:rootController];
    self.window.rootViewController = navigationController;

    [self.window makeKeyAndVisible];

    return YES;
}

@end

SearchViewController.h

//
//  SearchViewController.h
//  SearchNavigationItemAnimation
//

#import <UIKit/UIKit.h>


@interface SearchViewController : UIViewController

@end

SearchViewController.m

//
//  SearchViewController.m
//  SearchNavigationItemAnimation
//

#import "SearchViewController.h"

@interface SearchViewController () <UISearchControllerDelegate, UISearchResultsUpdating>
@property (nonatomic, strong) UISearchController *searchController;
@property (nonatomic, strong) UIBarButtonItem *rightBarButtonItem;
@end

@implementation SearchViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor lightGrayColor];
    self.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemBookmarks target:self action:@selector(navigationBarButtonItemAction)];

    UITableViewController *searchResultsController = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
    self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];
    self.searchController.delegate = self;
    self.searchController.searchResultsUpdater = self;
    self.searchController.hidesNavigationBarDuringPresentation = NO;

    self.navigationItem.titleView = self.searchController.searchBar;
    self.navigationItem.rightBarButtonItem = self.rightBarButtonItem;

    self.definesPresentationContext = YES;
}

- (void)willPresentSearchController:(UISearchController *)searchController
{
    [self.navigationItem setRightBarButtonItem:nil animated:true];
}

- (void)willDismissSearchController:(UISearchController *)searchController
{
    [self.navigationItem setRightBarButtonItem:self.rightBarButtonItem animated:true];
}

- (void)navigationBarButtonItemAction {
    float windowLayerSpeed = [UIApplication sharedApplication].keyWindow.layer.speed;
    [UIApplication sharedApplication].keyWindow.layer.speed = (windowLayerSpeed == 1.0) ? 0.1 : 1.0;
}

- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
}

@end

编辑

让我再解释一下这是怎么回事。

在没有添加 barButtonItem 的情况下,searchBar 占据了导航栏的整个宽度。当您触摸它时,它会激活并显示带有漂亮动画的取消按钮(搜索字段缩小,为从右侧滑入的取消按钮留出空间)。

在导航栏上有一个右键,如果你不尝试以任何方式添加it/remove it/modify它,它的工作方式是一样的。搜索栏占用除按钮宽度之外的所有 space,当它激活时,取消按钮从右侧和按钮下方滑入并落在它旁边(在搜索字段和现有的右键之间) ).一切都是动画并且工作正常。

现在,如果您想在取消按钮滑入时使右键消失,您必须为其框架设置动画。问题是搜索栏会自动尝试获取所有可用的 space,并且不会对其框架进行动画处理。因此,假设您想将按钮的帧宽度设置为零,搜索栏将立即扩展其宽度,而不是跟随您的动画。

这显然是一个错误,或者如果您更宽容一个尚未实现的功能...但它在 iOS7 和 UISearchDisplayController,Apple 在地图应用程序中执行此操作。所以我要求任何可行的解决方法,包括必要时私人 API 呼叫。

如果有人感兴趣,我设法使用 UISearchDisplayController 使其工作。参见 this sample project

不过,我仍然对适用于 UISearchController 的解决方案感兴趣。