iPhone:默认情况下隐藏UITableView搜索栏

时间:2009-07-04 02:45:24

标签: ios iphone uitableview user-interface

我使用Interface Builder创建了一个表视图,我在其中添加了库的搜索栏和搜索显示控制器以添加搜索功能。但是,IB会对其进行设置,以便在首次显示视图时在屏幕顶部显示该栏。

我想知道如何在默认情况下隐藏搜索栏,但仍可以使用表格视图滚动(请参阅Apple的Mail应用程序中的示例)。我尝试在scrollRectToVisible:animated:中调用viewDidLoad来向下滚动表格视图,但无济于事。隐藏搜索栏的首选方法是什么?

22 个答案:

答案 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。在viewDidLoadtableView.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"];
}