代码之家  ›  专栏  ›  技术社区  ›  Tim

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

  •  85
  • Tim  · 技术社区  · 15 年前

    我使用Interface Builder创建了一个表视图,在其中添加了库的搜索栏和搜索显示控制器,以添加搜索功能。但是,IB将其设置为在第一次显示视图时在屏幕顶部可以看到该条。

    我想知道如何在默认情况下隐藏搜索栏,但仍然可以在表视图中滚动(请参阅苹果的邮件应用程序以获取示例)。我试过打电话 scrollRectToVisible:animated: 在里面 viewDidLoad

    22 回复  |  直到 5 年前
        1
  •  116
  •   eonil    10 年前

    首先,请确保将UISearchBar添加到UITableView的tableHeaderView中,以便它与表的内容一起滚动,而不是固定在视图的顶部。

    [yourTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
    

    或使用Swift:

    yourTableView.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition: UITableViewScrollPosition.Top, animated: false)
    

    scrollToRowAtIndexPath 如果给定的indexPath未指向有效行(即,如果tableview为空),将引发异常。

        2
  •  45
  •   Jingshao Chen    9 年前

    不要将UISearchBar添加为UITableView的子视图,这不是必需的。

    - (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];
    }
    
        3
  •  25
  •   Sam Spencer    11 年前

    在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];
    

        4
  •  8
  •   Matej    11 年前

    这很好用。没有动画,并且是在 -viewDidLoad

     - (void)viewDidLoad {
         [super viewDidLoad];
         self.tableView.contentOffset = CGPointMake(0,  self.searchBar.frame.size.height - self.tableView.contentOffset.y);
     }
    

    注:

    searchBar @property 它链接到搜索栏。 如果没有,您可以使用 self.searchDisplayController.searchBar 相反

        5
  •  7
  •   Dasoga    8 年前

    我这样做:

    申报 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)
    
        6
  •  5
  •   kbpontius    9 年前

    所以,我正在使用 敏捷的 并增加了扩展:

    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)
                }
            }
        }
    }
    

    在里面 只要打电话:

    self.tableView.hideSearchBar()
    
        7
  •  5
  •   Brian    9 年前

    当没有足够的行填充tableView时,所有现有的解决方案都不适用于iOS 8,因为在这种情况下iOS将自动调整插入。(不过,如果行数足够多,则现有答案是好的)

    在这个问题上浪费了6个小时之后,我终于得到了这个解决方案。

    简言之,如果没有足够的单元格,则需要在tableView中插入空单元格,这样tableView的内容大小就足够大,iOS不会为您调整插入。

    以下是我在Swift中的做法:

    1.)声明一个变量 minimumCellNum 作为类属性

    var minimumCellNum: Int?
    

    最小细胞数 设定 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
    }
    

    tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)

    if tableView == self.tableView {
        if numOfYourRows < (indexPath.row + 1) {
            return
        }
        YOUR LOGIC OF SELECTING A CELL
    }
    

        8
  •  4
  •   grep    10 年前

    我有 searchBar 设为 tableHeaderView 在iOS7上的分组表上。在里面 viewDidLoad 我有 tableView.contentOffset = CGPointMake(0, 44); 保存 搜索条 最初是“隐藏的”。当用户向下滚动时 搜索条 是否显示了DSI

    目标: 单击“取消”按钮时隐藏搜索栏

    searchBarCancelButtonClicked(searchBar: UISearchBar!)

    这不起作用: [yourTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO]; tableView向上滚动太多,导致第0行在工具栏后面。

    这不起作用: tableView.ContentOffset = CGPointMake(0, 44)

    这不起作用: tableView.ContentOffset = CGPointMake(0, searchBar.frame.size.height)

    这不起作用: tableView.setContentOffset(CGPointMake(0, 44), animated: true); tableView再次向上滚动过多,导致第0行位于工具栏后面。

    这部分起了作用: tableView.setContentOffset(CGPointMake(0, 0) 但是 titleForHeaderInSection

    这起到了作用: tableView.setContentOffset(CGPointMake(0, -20)

        9
  •  4
  •   RyanJM    8 年前

    如果正在设置,则不起作用 estimatedRowHeight project 显示问题,我创建了一个 radar

        10
  •  3
  •   dibi    10 年前

    请注意,如果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)];
    }
    
        11
  •  2
  •   p0lAris    10 年前

    老实说,没有一个答案(对我来说)真正解决了这个问题。如果您的表视图没有行或行高不同,则这些答案是不够的。

    唯一有效的方法是:

    - (void)viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:animated];
        self.tableView.contentOffset = (CGPoint){.y =  self.tableView.contentOffset.y + self.searchController.searchBar.frame.size.height};
    }
    
        12
  •  2
  •   Confused Vorlon    5 年前

    这个 scrollToRowAtIndexPath 如果表中没有行,方法将导致崩溃。

    UITableView只是一个滚动视图,因此您可以简单地更改内容偏移量。

    这将检查您是否有作为tableHeaderView的内容,并假设您确实滚动以隐藏它

        if let searchHeight = tableView.tableHeaderView?.frame.height {
            tableView.setContentOffset(CGPoint.init(x: 0, y:searchHeight ), animated: false)
        }
    
        13
  •  1
  •   Chilly Zhong    15 年前

    -(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];
    }
    

    希望这有帮助:-)

        14
  •  1
  •   LightMan    11 年前

    更改tableView的边界,这可以在内部完成 viewDidLoad 另外,您不必担心表是否为空(以避免异常)。

    CGRect newBounds = self.tableView.bounds;
    newBounds.origin.y = newBounds.origin.y + self.searchBar.bounds.size.height;
    self.tableView.bounds = newBounds;
    

    一旦用户向下滚动表格,搜索栏就会出现并正常运行

        15
  •  1
  •   kbpontius    9 年前

    这个问题的其他答案要么对我根本不起作用,要么在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 contentOffset ,又名滚动位置,为 0 )。如果是,它只需向下滚动搜索栏的高度即可。如果搜索栏不可见(请考虑 桌面视图 桌面视图

    旁注

        16
  •  1
  •   drv    9 年前

    如果您的表格始终至少有一行,只需滚动到表格的第一行,搜索栏将自动隐藏。

    let firstIndexPath = NSIndexPath(forRow: 0, inSection: 0)
    

    self.tableView.SelectRowatineXpath(firstIndexPath,动画:false,scrollPosition:.Top)

    如果你把上面的代码放在 viewDidLoad ,它将抛出一个错误,因为tableView尚未加载,因此您必须将其放入 视图显示

    如果你戴上它 视图显示 ,每次打开tableView时,它都会滚动到顶部。

    首先在视图控制器类中定义一个名为isInitialLoad的变量,并将其设置为“true”:

    var isInitialLoad = true
    

    然后检查isInitialLoad在上是否为true 视图显示 如果为true,则滚动到顶部并将isInitialLoad变量设置为false:

    if isInitialLoad {
                let firstIndexPath = NSIndexPath(forRow: 0, inSection: 0)
                self.tableView.selectRowAtIndexPath(firstIndexPath, animated: false, scrollPosition: .Top)
    
                isInitialLoad = false
            }
    
        17
  •  1
  •   Ashu    8 年前

    下面的代码为我工作

    self.tableView.contentOffset = CGPointMake(0.0, 44.0);
    
        18
  •  1
  •   Abdur Rahman    7 年前

    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)
        }
    }
    

    这就像一个符咒。内容偏移设置是为了平滑滚动

        19
  •  0
  •   fujianjin6471    8 年前

    别忘了带 导航栏 考虑到。“我的表视图”控制器嵌入在导航控制器中 viewDidAppear :

    tableView.contentOffset = CGPointMake(0, -20) // -20 = 44 (search bar height) - 20 (status bar height) - 44 (navigation bar height)
    

        20
  •  0
  •   stakahop    8 年前

    对于Swift:

    只需将tableview内容设置为y偏移,这应该和搜索栏的高度类似。

    self.tableView.contentOffset = CGPointMake(0, self.searchController.searchBar.frame.size.height)
    
        21
  •  0
  •   Johannes Knust    8 年前

    斯威夫特3

    也适用于空表!

    在我的环境中,我通过xib文件加载自定义单元格,行高是自动设置的。

        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)
    }
    
        22
  •  0
  •   slobodans    7 年前

    我也有类似的问题。我发现解决这个问题的唯一方法是在UITableView contentOffset属性上使用键值观察器。

    经过一些调试后,我意识到,当表视图内容大小小于表视图时,问题就会出现。当打开视图时,我启动KVO。 并在视图出现0.3秒后调度停止KVO。每次contentOffset变为0.0时,KVO都会做出反应并在搜索栏高度上设置contentOffset。 我在0.3秒后停止KVO asynchronous,因为即使在视图出现之后,视图布局也会重置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"];
    }