我使用Interface Builder创建了一个表视图,我在其中添加了库的搜索栏和搜索显示控制器以添加搜索功能。但是,IB会对其进行设置,以便在首次显示视图时在屏幕顶部显示该栏。
我想知道如何在默认情况下隐藏搜索栏,但仍可以使用表格视图滚动(请参阅Apple的Mail应用程序中的示例)。我尝试在scrollRectToVisible:animated:
中调用viewDidLoad
来向下滚动表格视图,但无济于事。隐藏搜索栏的首选方法是什么?
答案 0 :(得分:115)
首先确保将UISearchBar添加到UITableView的tableHeaderView中,以便它与表的内容一起滚动,并且不会固定到视图的顶部。
搜索栏不计入tableview中的一行,因此如果您将tableview的顶部滚动到第一行,它会“隐藏”搜索栏:
[yourTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
或在Swift中:
yourTableView.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition: UITableViewScrollPosition.Top, animated: false)
确保在包含数据之前不滚动tableview(如果给定的indexPath没有指向有效行(例如,如果tableview为空),scrollToRowAtIndexPath
将引发异常。)
答案 1 :(得分:45)
不要将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];
}
答案 2 :(得分:25)
在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];
答案 3 :(得分:7)
这个解决方案有很多答案,但是对我来说都不是很好。
这完美无缺。没有动画,并在-viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.contentOffset = CGPointMake(0, self.searchBar.frame.size.height - self.tableView.contentOffset.y);
}
注意:强>
代码假设您拥有链接到搜索栏的searchBar
@property
。
如果没有,您可以使用self.searchDisplayController.searchBar
代替
答案 4 :(得分:6)
对于Swift 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)
答案 5 :(得分:5)
我的目标是在加载视图控制器时隐藏添加到storyboard中的简单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()
答案 6 :(得分:4)
以上都不适合我,所以如果有人会遇到同样的问题。
我在iOS7上的分组表格中将searchBar
设置为tableHeaderView
。在viewDidLoad
我tableView.contentOffset = CGPointMake(0, 44);
让searchBar
最初“隐藏”。当用户向下滚动时searchBar
是dsiplayed
目标:在取消按钮上隐藏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
落后于工具栏
此工作: tableView.setContentOffset(CGPointMake(0, -20)
似乎不符合逻辑但只有-20将其移动到正确的位置
答案 7 :(得分:4)
当没有足够的行来填充tableView时,所有现有解决方案都无法在iOS 8上工作,因为iOS会在这种情况下自动调整插入。 (当有足够的行时,现有答案很好)
在这个问题上浪费了6个小时之后,我终于得到了这个解决方案。
简而言之,如果没有足够的单元格,则需要在tableView中插入空单元格,因此tableView的内容大小足够大,以至于iOS不会为您调整插入内容。
以下是我在Swift中的表现:
1。)将变量minimumCellNum
声明为类属性
var minimumCellNum: Int?
2。)计算minimumCellNum
并在tableView.contentOffset
viewWillAppear
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.。)在故事板和selection
None
属性为tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
的空单元格
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的解决方法。我想知道是否有更整洁的解决方案。
答案 8 :(得分:4)
内容偏移是可行的方法,但它不会在100%的时间内起作用。
如果将estimatedRowHeight
设置为固定数字,则无效。我还不知道这方面的工作。我创建了project来显示问题,并且我已经与Apple创建了radar。
如果您想快速了解如何设置它的示例,请查看项目。
答案 9 :(得分:3)
请注意,如果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)];
}
答案 10 :(得分:2)
老实说,没有一个答案真正解决了这个问题(对我而言)。如果您的表格视图没有行或行高不同,这些答案就不够了。
唯一有效的方法:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.tableView.contentOffset = (CGPoint){.y = self.tableView.contentOffset.y + self.searchController.searchBar.frame.size.height};
}
答案 11 :(得分:1)
如果表中有零行,scrollToRowAtIndexPath
方法会导致崩溃。
UITableView只是一个滚动视图,因此您只需更改内容偏移量。
这会检查你有一个搜索栏作为你的tableHeaderView,并假设你滚动隐藏它
if let searchHeight = tableView.tableHeaderView?.frame.height {
tableView.setContentOffset(CGPoint.init(x: 0, y:searchHeight ), animated: false)
}
答案 12 :(得分:1)
我尝试设置内容偏移量和scrollToIndexpath,但没有任何效果令人满意。我从viewDidLoad中删除了tableHeaderView的设置为searchBar,并将其设置在scrollview委托中,如下所示
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)
}
}
这就像魅力一样。内容偏移设置用于平滑滚动
答案 13 :(得分:1)
下面的代码对我有用
self.tableView.contentOffset = CGPointMake(0.0, 44.0);
答案 14 :(得分:1)
如果您的表格总是至少有一行,只需滚动到表格的第一行,搜索栏就会自动隐藏。
let firstIndexPath = NSIndexPath(forRow: 0, inSection: 0)
self.tableView.selectRowAtIndexPath(firstIndexPath,animated:false,scrollPosition:.Top)
如果您将上述代码放在 viewDidLoad 上,则会抛出错误,因为尚未加载tableView,因此您必须将其放入 viewDidAppear 因为到目前为止,tableView已经加载了。
如果你把它放在 viewDidAppear 上,每次打开tableView时它都会滚动到顶部。
如果tableView保持打开状态,也许你不想要这种行为,就像它是一个UITabBar View Controller,或者当你做一个segue然后再回来时。如果您只是希望它在初始加载时滚动到顶部,您可以创建一个变量来检查它是否是初始加载,以便它只滚动到顶部一次。
首先在视图控制器类中定义一个名为isInitialLoad的变量,并将其设置为&#34; true&#34;:
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
}
答案 15 :(得分:1)
这个问题的其他答案对我来说根本不起作用,当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是否可见(意味着y
的{{1}}位置,即滚动位置contentOffset
})。如果是,它只是向下滚动searchBar的高度。如果searchBar不可见(想想0
中的一个更大的项目列表),那么它就不会尝试滚动tableView
,因为当你从a返回时这会弄乱定位嵌套的订单项。
旁注
我建议将此代码放在一个单独的方法中,以确保单一责任,并让您可以在代码中随时调用它。
答案 16 :(得分:1)
更改tableView的边界,这可以在viewDidLoad
内完成,另外你不必担心表是否为空(以避免异常)。
CGRect newBounds = self.tableView.bounds;
newBounds.origin.y = newBounds.origin.y + self.searchBar.bounds.size.height;
self.tableView.bounds = newBounds;
一旦用户向下滚动表格,搜索栏就会出现并且表现正常
答案 17 :(得分:1)
我发现当“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];
}
希望这会有所帮助: - )
答案 18 :(得分:0)
不要忘记考虑状态栏和导航栏。我的表视图控制器嵌入在viewDidAppear
:
tableView.contentOffset = CGPointMake(0, -20) // -20 = 44 (search bar height) - 20 (status bar height) - 44 (navigation bar height)
为我工作。
答案 19 :(得分:0)
对于Swift:
只需将tableview内容y偏移,这应该与搜索栏的高度相同。
self.tableView.contentOffset = CGPointMake(0, self.searchController.searchBar.frame.size.height)
答案 20 :(得分:0)
Swift 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)
}
答案 21 :(得分:0)
我有类似的问题。我找到解决此问题的唯一方法是在UITableView contentOffset属性上使用键值观察器。
经过一些调试后,我意识到只要表视图内容大小小于tableview就会出现问题。我在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"];
}