使用 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
的解决方案感兴趣。
我正在尝试重现类似于地图应用程序之一的搜索界面。
我在 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
的解决方案感兴趣。