我使用 Interface Builder 创建了一个表格视图,我在其中添加了库的搜索栏和搜索显示控制器以添加搜索功能。但是,IB 对其进行了设置,以便在第一次显示视图时,该栏在屏幕顶部可见。
我想知道如何在默认情况下隐藏搜索栏,但仍然可以使用表格视图滚动(请参阅 Apple 的邮件应用程序以获取示例)。我尝试在 viewDidLoad
中调用 scrollRectToVisible:animated:
以向下滚动表格视图,但无济于事。默认情况下隐藏搜索栏的首选方式是什么?
首先确保将 UISearchBar 添加到 UITableView 的 tableHeaderView 中,以便它与表格的内容一起滚动并且不固定在视图的顶部。
搜索栏不计为表格视图中的一行,因此如果您将表格视图的顶部滚动到第一行,它会“隐藏”搜索栏:
[yourTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
或在斯威夫特:
yourTableView.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition: UITableViewScrollPosition.Top, animated: false)
确保在 tableview 包含数据之前不要滚动它(如果给定的 indexPath 不指向有效行(即如果 tableview 为空),scrollToRowAtIndexPath
将引发异常)。
不要将 UISearchBar 添加为 UITableView 的子视图,这不是必需的。
UITableView 有一个 tableHeaderView 属性非常适合:
- (void) viewDidLoad {
[super viewDidLoad];
self.searchBar = [[[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)] autorelease];
self.searchBar.showsCancelButton = YES;
self.searchBar.delegate = self;
self.tableView.tableHeaderView = self.searchBar;
}
如果您不想在默认情况下看到它:
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.tableView setContentOffset:CGPointMake(0, 44)];
}
我也得到了取消按钮来再次隐藏它......(并移除键盘)
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
[self.tableView setContentOffset:CGPointMake(0, 44) animated:YES];
[self.searchBar resignFirstResponder];
}
viewWillAppear
中是个坏主意,因为它会在您每次导航回视图时运行。这意味着您的 tableview 将慢慢缩小。恼人的错误!
Tim 和 Joe D'Andrea 在评论中提到了 contentOffset,但通过添加动画来隐藏搜索栏,这有点扩展。我注意到搜索栏消失有点出乎意料。
对于那些想要以 iOS 4.0 及更高版本为目标的用户,请尝试以下操作:
[UIView animateWithDuration:0.4 animations:^{
self.tableView.contentOffset = CGPointMake(0, self.searchDisplayController.searchBar.frame.size.height);
} completion:nil];
上一个答案:
[UIView beginAnimations:@"hidesearchbar" context:nil];
[UIView setAnimationDuration:0.4];
[UIView setAnimationBeginsFromCurrentState:YES];
self.tableView.contentOffset = CGPointMake(0, self.searchDisplayController.searchBar.frame.size.height);
[UIView commitAnimations];
viewDidAppear:
而不是 viewDidLoad
中实现它,我在不需要动画的情况下已经成功了。
这个解决方案有很多答案,但是没有一个对我很有效。
这完美地工作。没有动画,在 -viewDidLoad
完成
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.contentOffset = CGPointMake(0, self.searchBar.frame.size.height - self.tableView.contentOffset.y);
}
笔记:
代码假定您有链接到搜索栏的 searchBar
@property
。如果没有,您可以改用 self.searchDisplayController.searchBar
-viewWillAppear
不起作用,我不确定你将如何解决这个问题。当标签控制器切换到视图时它会被调用吗?
对于斯威夫特 3+
我这样做了:
声明这个 var
:
var searchController = UISearchController()
在 viewDidLoad()
方法中
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = true
searchController.searchBar.placeholder = NSLocalizedString("Search", comment: "")
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
tableView.contentOffset = CGPoint(x: 0, y: searchController.searchBar.frame.size.height)
我的目标是在加载视图控制器时隐藏添加到情节提要中普通 TableView 样式的 tableHeaderView 的搜索栏,并在用户向下滚动 UITableView 顶部时显示该栏。所以,我正在使用 Swift 并添加了扩展:
extension UITableView {
func hideSearchBar() {
if let bar = self.tableHeaderView as? UISearchBar {
let height = CGRectGetHeight(bar.frame)
let offset = self.contentOffset.y
if offset < height {
self.contentOffset = CGPointMake(0, height)
}
}
}
}
在 viewDidLoad() 中只需调用:
self.tableView.hideSearchBar()
当没有足够的行来填充 tableView 时,所有现有的解决方案都不适用于我在 iOS 8 上,因为 iOS 会在这种情况下自动调整插图。 (但是,当有足够的行时,现有答案很好)
在这个问题上浪费了大约 6 个小时后,我终于得到了这个解决方案。
简而言之,如果没有足够的单元格,则需要将空单元格插入到tableView中,因此tableView的内容大小足够大,iOS不会为您调整inset。
以下是我在 Swift 中的做法:
1.) 将变量 minimumCellNum
声明为类属性
var minimumCellNum: Int?
2.) 计算 minimumCellNum
并在 viewWillAppear
中设置 tableView.contentOffset
let screenHeight = Int(UIScreen.mainScreen().bounds.height)
// 101 = Height of Status Bar(20) + Height of Navigation Bar(44) + Height of Tab Bar(49)
// you may need to subtract the height of other custom views from the screenHeight. For example, the height of your section headers.
self.minimumCellNum = (screenHeight - 103 - heightOfOtherCustomView) / heightOfYourCell
self.tableView.contentOffset = CGPointMake(0, 44)
3.) 在 tableView(tableView: UITableView, numberOfRowsInSection section: Int))
let numOfYourRows = YOUR LOGIC
if numOfYourRows > minimumCellNum {
return numOfYourRows
} else {
return minimumCellNum!
}
4.) 在情节提要和 tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
中注册一个 selection
属性为 None
的空单元格
if indexPath.row < numOfYourRows {
return YOUR CUSTOM CELL
} else {
let cell = tableView.dequeueReusableCellWithIdentifier("EmptyCell", forIndexPath: indexPath) as! UITableViewCell
return cell
}
5.) 在 tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
if tableView == self.tableView {
if numOfYourRows < (indexPath.row + 1) {
return
}
YOUR LOGIC OF SELECTING A CELL
}
这不是一个完美的解决方案,但它是在 iOS 8 上真正适合我的唯一解决方法。我想知道是否有更简洁的解决方案。
以上都不适合我,所以以防万一有人遇到同样的问题。
我在 iOS7 的分组表上将 searchBar
设置为 tableHeaderView
。在 viewDidLoad
我有 tableView.contentOffset = CGPointMake(0, 44);
保持 searchBar
最初“隐藏”。当用户向下滚动时显示 searchBar
目标:在取消按钮点击时隐藏搜索栏
在 searchBarCancelButtonClicked(searchBar: UISearchBar!)
这不起作用: [yourTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
tableView 向上滚动太多,导致第 0 行落后于 toolBar。
这不起作用: tableView.ContentOffset = CGPointMake(0, 44)
- 没有任何反应
这不起作用: tableView.ContentOffset = CGPointMake(0, searchBar.frame.size.height)
- 没有任何反应
这不起作用: tableView.setContentOffset(CGPointMake(0, 44), animated: true);
tableView 再次向上滚动太多,导致第 0 行落后于 toolBar。
这部分工作: tableView.setContentOffset(CGPointMake(0, 0)
但 titleForHeaderInSection
落后于 toolBar
这行得通: tableView.setContentOffset(CGPointMake(0, -20)
似乎不合逻辑,但只有 -20 将其移至正确位置
CGRectGetHeight(searchBar.bounds)
?
ContentOffset
解决方案均无效
请注意,如果 tableview 中没有数据,则接受的答案将崩溃。在某些情况下,将其添加到 viewDidLoad 可能不起作用。
[yourTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO]; // crashes if no rows/data
因此,改为添加这行代码:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[yourTableView setContentOffset:CGPointMake(0, self.searchDisplayController.searchBar.frame.size.height)];
}
老实说,没有一个答案真正解决了这个问题(对我来说)。如果您的表格视图没有行或行高不同,那么这些答案是不够的。
唯一有效的:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.tableView.contentOffset = (CGPoint){.y = self.tableView.contentOffset.y + self.searchController.searchBar.frame.size.height};
}
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
。
如果表中有零行,scrollToRowAtIndexPath
方法会导致崩溃。
UITableView 只是一个滚动视图,因此您可以简单地更改内容偏移量。
这会检查您是否有一些东西作为您的 tableHeaderView,并假设您滚动隐藏它
if let searchHeight = tableView.tableHeaderView?.frame.height {
tableView.setContentOffset(CGPoint.init(x: 0, y:searchHeight ), animated: false)
}
我发现当 tableView 为空白时,“Notes”应用程序无法搜索项目。所以我认为它最初只是使用 -(void)addSubview:(UIView *)view
添加一个空白表。当您将项目添加到其数据源数组时,它将运行另一段代码来加载 tableView。
所以我的解决方案是:
if([self.arrayList count] > 0)
{
[self.tableView reloadData]; //use jdandrea's code to scroll view when cell==nil in cellForRowAtIndexPath
self.tableView.scrollEnabled = YES;
}
else
{
tableBlank = [[UITableView alloc]initWithFrame:CGRectMake(0,0,320,416) style:UITableViewStylePlain] autorelease];
tableBlank.delegate = self;
tableBlank.dataSource = self;
[self.view addSubview:tableBlank];
}
希望这可以帮助 :-)
更改 tableView 的边界,这可以在 viewDidLoad
内完成,而且您不必担心表是否为空(以避免异常)。
CGRect newBounds = self.tableView.bounds;
newBounds.origin.y = newBounds.origin.y + self.searchBar.bounds.size.height;
self.tableView.bounds = newBounds;
用户向下滚动表格后,搜索栏将出现并正常运行
这个问题的其他答案要么对我根本不起作用,要么在 tableView 有 0 行时出现奇怪的行为,要么在父项和嵌套行项之间来回移动时弄乱了滚动位置。这对我有用(目标是在加载时隐藏 UISearchBar):
public override func viewWillAppear(animated: Bool) {
if self.tableView.contentOffset.y == 0 {
self.tableView.contentOffset = CGPoint(x: 0.0, y: self.searchBar.frame.size.height)
}
}
解释
每当 tableView
出现时,此代码都会检查 UISearchBar 是否可见(意味着 contentOffset
的 y
位置,也就是滚动位置,是 0
)。如果是,它只是向下滚动 searchBar 的高度。如果 searchBar 不可见(想想 tableView
中的较大项目列表),则它不会尝试滚动 tableView
,因为这会在您从嵌套订单项返回时弄乱定位。
旁注我建议将此代码放在一个单独的方法中,以确保单一职责并让您可以在代码中随时调用它的可重用性。
如果您的表格总是至少有一行,只需滚动到表格的第一行,搜索栏就会自动隐藏。
let firstIndexPath = NSIndexPath(forRow: 0, inSection: 0)
self.tableView.selectRowAtIndexPath(firstIndexPath, 动画: false, scrollPosition: .Top)
如果你把上面的代码放在viewDidLoad上,它会抛出一个错误,因为tableView还没有加载,所以你必须把它放在viewDidAppear中,因为此时tableView已经加载了。
如果你把它放在 viewDidAppear 上,每次打开 tableView 时它都会滚动到顶部。
如果 tableView 保持打开状态,例如当它是 UITabBar 视图控制器或执行 segue 然后返回时,您可能不希望出现这种行为。如果您只想让它在初始加载时滚动到顶部,您可以创建一个变量来检查它是否是初始加载,以便它只滚动到顶部一次。
首先在视图控制器类中定义一个名为 isInitialLoad 的变量并将其设置为“true”:
var isInitialLoad = true
然后检查 viewDidAppear 上的 isInitialLoad 是否为 true,如果为 true,则滚动到顶部并将 isInitialLoad 变量设置为 false:
if isInitialLoad {
let firstIndexPath = NSIndexPath(forRow: 0, inSection: 0)
self.tableView.selectRowAtIndexPath(firstIndexPath, animated: false, scrollPosition: .Top)
isInitialLoad = false
}
下面的代码对我有用
self.tableView.contentOffset = CGPointMake(0.0, 44.0);
我尝试设置内容偏移量和 scrollToIndexpath,但没有任何效果令人满意。我从 viewDidLoad 中删除了 tableHeaderView 作为 searchBar 的设置,并将其设置在滚动视图委托中,如下所示
override func scrollViewWillBeginDragging(scrollView: UIScrollView) {
if scrollView.contentOffset.y < 0 && tableView.tableHeaderView == nil {
tableView.tableHeaderView = searchController.searchBar
tableView.setContentOffset(CGPointMake(0, scrollView.contentOffset.y + searchController.searchBar.frame.size.height), animated: false)
}
}
这就像一个魅力。内容偏移设置是为了平滑滚动
不要忘记考虑状态栏和导航栏。我的表格视图控制器嵌入在 viewDidAppear
中的导航控制器中:
tableView.contentOffset = CGPointMake(0, -20) // -20 = 44 (search bar height) - 20 (status bar height) - 44 (navigation bar height)
为我工作。
对于斯威夫特:
只需使 tableview 内容 y 偏移,这应该像搜索栏的高度。
self.tableView.contentOffset = CGPointMake(0, self.searchController.searchBar.frame.size.height)
斯威夫特 3
也适用于空表!
在我的环境中,我通过 xib 文件加载自定义单元格,并且 rowHeight 是自动设置的。
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
self.tableView.contentOffset = CGPoint(x: 0, y: self.tableView.contentOffset.y + self.searchController.searchBar.bounds.height)
}
我有类似的问题。我发现解决此问题的唯一方法是在 UITableView contentOffset 属性上使用键值观察器。
经过一些调试后,我意识到如果表视图内容大小小于表视图,就会出现问题。我在 viewWillAppear 上启动 KVO。并在视图出现 0.3 秒后停止 KVO。每次 contentOffset 变为 0.0 时,KVO 都会做出反应并在搜索栏高度上设置 contentOffset。我在 0.3 秒后停止 KVO 异步,因为即使在视图出现后视图布局也会重置 contentOffset。
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.tableView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
}
-(void)viewDidAppear:(BOOL)animated{
__weak typeof (self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[weakSelf.tableView removeObserver:self forKeyPath:@"contentOffset"];});
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
if ([keyPath isEqualToString:@"contentOffset"] && self.tableView.contentOffset.y == 0.0) {
self.tableView.contentOffset = CGPointMake(0, CGRectGetHeight(self.tableView.tableHeaderView.frame));
}
}
-(void)dealloc {
[self.tableView removeObserver:self forKeyPath:@"contentOffset"];
}
contentOffset
都会中断。我不推荐它。