有人知道这可能是如何完成的吗?我想知道苹果是否将搜索栏和表格都放在一个父滚动视图中,但我想知道是否可能比那更简单。
Bob 的答案颠倒了:正确的应该是 MIN(0, scrollView.contentOffset.y)。
此外,为了正确支持调整大小(当旋转时会发生),其他框架值应该被重用。
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
UISearchBar *searchBar = searchDisplayController.searchBar;
CGRect rect = searchBar.frame;
rect.origin.y = MIN(0, scrollView.contentOffset.y);
searchBar.frame = rect;
}
您可以将搜索栏放在表头,并为表格视图实现 - (void)scrollViewDidScroll:(UIScrollView *)scrollView 委托方法。像这样做应该可以:
-(void) scrollViewDidScroll:(UIScrollView *)scrollView {
searchBar.frame = CGRectMake(0,MAX(0,scrollView.contentOffset.y),320,44);
}
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
/* Search controller parameters */
searchController.searchResultsUpdater = self // This protocol allows your class to be informed as text changes within the UISearchBar.
searchController.dimsBackgroundDuringPresentation = false // In this instance,using current view to show the results, so do not want to dim current view.
definesPresentationContext = true // ensure that the search bar does not remain on the screen if the user navigates to another view controller while the UISearchController is active.
let tableHeaderView: UIView = UIView.init(frame: searchController.searchBar.frame)
tableHeaderView.addSubview(searchController.searchBar)
self.tableView.tableHeaderView = tableHeaderView
}
override func scrollViewDidScroll(scrollView: UIScrollView) {
let searchBar:UISearchBar = searchController.searchBar
var searchBarFrame:CGRect = searchBar.frame
if searchController.active {
searchBarFrame.origin.y = 10
}
else {
searchBarFrame.origin.y = max(0, scrollView.contentOffset.y + scrollView.contentInset.top)
}
searchController.searchBar.frame = searchBarFrame
}
class SearchBarView: UIView {
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
for subview in subviews {
if !subview.userInteractionEnabled { continue }
let newPoint = subview.convertPoint(point, fromView: self)
if CGRectContainsPoint(subview.bounds, newPoint) {
return subview.hitTest(newPoint, withEvent: event)
}
}
return super.hitTest(point, withEvent: event)
}
}
现在,我们有一个名为SearchBarView
的UIView子类,它能够接收发生在其边界之外的触摸事件。
其次,在视图控制器加载其视图时,我们应该将搜索栏放入这个新视图中:
class TableViewController: UITableViewController {
private let searchBar = UISearchBar(frame: CGRectZero)
...
override func viewDidLoad() {
super.viewDidLoad()
...
searchBar.sizeToFit()
let searchBarView = SearchBarView(frame: searchBar.bounds)
searchBarView.addSubview(searchBar)
tableView.tableHeaderView = searchBarView
}
}
override func scrollViewDidScroll(scrollView: UIScrollView) {
searchBar.frame.origin.y = max(0, scrollView.contentOffset.y)
}
以下是结果:
--
重要提示:如果你的表视图有分组,它们可能会遮挡搜索栏,因此每当表视图的bounds
更新时,你需要将搜索栏置于它们之上。
viewDidLayoutSubviews
是一个不错的位置来完成此操作:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
...
if let tableHeaderView = tableView.tableHeaderView {
tableView.bringSubviewToFront(tableHeaderView)
}
}
--
希望这能帮到你。你可以从这里下载示例项目。如果您想完全模拟Game Center中的搜索栏,则需要进行一步操作。
如果您使用friedenberg的优秀答案以及评论中提到的iOS 6+的修正版本followben,您仍然需要调整搜索栏本身处于活动状态时的功能。
在Game Center中,当您向下滚动表格时,搜索栏将随之滚动,但是当您尝试向上滚动超出表格边界时,搜索栏将保持固定在导航栏下方。但是,当搜索栏处于活动状态且正在显示搜索结果时,搜索栏不再随表格滚动; 它保持在导航栏下方固定不动。
这是实现此功能的完整代码(适用于iOS 6+)。 (如果您的目标是iOS 5或更低版本,则不需要在UIView中包装UISearchBar)
CustomTableViewController.m
- (void)viewDidLoad
{
UISearchBar *searchBar = [[UISearchBar alloc] init];
...
UIView *tableHeaderView = [[UIView alloc] initWithFrame:searchBar.frame];
[tableHeaderView addSubview:searchBar];
[self.tableView setTableHeaderView:tableHeaderView];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
UISearchBar *searchBar = self.tableView.tableHeaderView.subviews.lastObject;
CGRect searchBarFrame = searchBar.frame;
/*
* In your UISearchBarDelegate implementation, set a boolean flag when
* searchBarTextDidBeginEditing (true) and searchBarTextDidEndEditing (false)
* are called.
*/
if (self.inSearchMode)
{
searchBarFrame.origin.y = scrollView.contentOffset.y;
}
else
{
searchBarFrame.origin.y = MIN(0, scrollView.contentOffset.y);
}
searchBar.frame = searchBarFrame;
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
self.inSearchMode = YES;
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
self.inSearchMode = NO;
}
现在,当搜索栏处于非活动状态时,它将随着表格一起移动,并在尝试超出表格边界时保持固定。当激活时,它将像游戏中心一样保持固定位置。
UINavigationController
中使用它?在这种情况下,新的iOS7“导航栏下内容”就会发挥作用。scrollView.contentOffset.y也包含此偏移量,因此当在tableview顶部时,实际上会返回-64而不是0。因此,MIN行应该写成MIN(0, scrollView.contentOffset.y + scrollView.contentInset.top)
。 - Tyson这里的所有其他答案都为我提供了有用的信息,但是在使用iOS 7.1时,它们都不起作用。以下是一个对我有效的简化版本:
MyViewController.h:
@interface MyViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, UISearchDisplayDelegate> {
}
@end
MyViewController.m:
@implementation MyViewController {
UITableView *tableView;
UISearchDisplayController *searchDisplayController;
BOOL isSearching;
}
-(void)viewDidLoad {
[super viewDidLoad];
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
searchBar.delegate = self;
searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
searchDisplayController.delegate = self;
searchDisplayController.searchResultsDataSource = self;
searchDisplayController.searchResultsDelegate = self;
UIView *tableHeaderView = [[UIView alloc] initWithFrame:searchDisplayController.searchBar.frame];
[tableHeaderView addSubview:searchDisplayController.searchBar];
[tableView setTableHeaderView:tableHeaderView];
isSearching = NO;
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
UISearchBar *searchBar = searchDisplayController.searchBar;
CGRect searchBarFrame = searchBar.frame;
if (isSearching) {
searchBarFrame.origin.y = 0;
} else {
searchBarFrame.origin.y = MAX(0, scrollView.contentOffset.y + scrollView.contentInset.top);
}
searchDisplayController.searchBar.frame = searchBarFrame;
}
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
isSearching = YES;
}
-(void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
isSearching = NO;
}
@end
scrollViewDidScroll:
中将scrollView.contentInset.top
替换为常量,以允许搜索栏在刷新动画上滚动。 private let tableView = UITableView(frame: .zero, style: .plain)
private let searchBar = UISearchBar(frame: CGRect .zero)
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.contentInset = UIEdgeInsets(top: 44.0, left: 0.0, bottom: 0.0, right: 0.0)
searchBar.delegate = self
view.addSubview(tableView)
view.addSubview(searchBar)
NSLayoutConstraint.activate([
searchBar.heightAnchor.constraint(equalToConstant: 44.0),
searchBar.leadingAnchor.constraint(equalTo: view.leadingAnchor),
searchBar.trailingAnchor.constraint(equalTo: view.trailingAnchor),
searchBar.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor)
])
}
UISearchBar
作为tableHeaderView
时,在-scrollViewDidScroll:
中直接操纵它的框架(Frame) 在 iOS 5.x 上可以工作,但在 iOS 6 上不行。为了使其正常工作,我不得不将搜索栏包装在一个普通的UIView
中,并将其添加为表头。 - followben