如果推送控制器隐藏标签栏,UISearchBar会跳转

我的UI结构如下:

UITabBarControllerTBC ) – > UINavigationControllerNC ) – > UITableViewControllerTVC

(为了简化示例,我们可以说TBC在其viewControllers数组上只有一个控制器viewControllers

我的TVCUISearchBar作为其表格标题,当TVC出现时,我通过设置表格视图内容偏移量隐藏NC导航栏下方的搜索栏。

当用户点击TVC中的一个单元时,按下另一个视图控制器( VC )并用VC.hidesBottomBarWhenPushed = YES;隐藏标签栏VC.hidesBottomBarWhenPushed = YES;

现在有一种非常烦人的行为,我不知道如何解决:
当用户点击VC中的后退按钮返回TVC时 ,即使在按下VC之前隐藏了(在导航栏下方),搜索栏也会跳转到可见状态。

仅当TVC没有足够的行来填充屏幕时才会出现此效果,如果屏幕上有某个位置,它就像搜索栏一样强制自己可见。 但它真的看起来很糟糕和马车。

我上传了一个演示问题的简单项目 ,它与我在问题中描述的结构相同。
为方便起见,我添加了两个小节按钮,“隐藏栏”按钮为您隐藏搜索栏,“切换计数”按钮切换表格视图行数,以certificate只有少数项目才会出现问题。

好吧..在我看来你偶然发现了一个错误。 它应该通过apples bugreporter( 这里 )报告。

我做了一个简单易懂的童话工作,但请记住,这一个解决方法。 这将有效,但如果您有/向tableView添加其他控件,则可能需要查看它。 它应该是安全的(不是随意的),并且它不是最丑陋的解决方法,所以我认为在发布中使用它是好的。 我已经在这里上传了相同的项目 ,你可以继续下载它,你可能会理解我做了什么。 我将解释(非常详细)我在这里实际思考和完成的内容,以防下载链接在将来消失:

思路:

正如simalone所说,问题是当hidesBottomBarWhenPushed设置为YES ,它会调用另外一个viewDidLayoutSubviews ,它会以某种方式重置你当前的状态。 我们需要覆盖viewDidLayoutSubviews ,并检查我们是否正在布局子视图, 因为我们来自ViewController ,或者它只是一个常规调用。 当我们确定调用确实是因为我们从ViewController返回时,我们需要隐藏搜索栏(仅当它被隐藏之前)。

当我们从ViewController返回时,对TableViewController viewDidLayoutSubviews进行了三次调用。 我猜第一个是tableView ,似乎第二个调用是’for’(或者更确切地说 )tabBar。 第二个是将搜索searchBar向下移动的searchBar 。 我不知道第三个电话是什么,但我们可以忽略它。

所以现在我们需要在viewDidLayoutSubviews检查三件事:我们需要检查是否从ViewController返回,我们需要在推送之前检查searchBar是否被隐藏(如果它现在应该被隐藏),我们需要检查这是对这种方法的第二次调用。

首先要做的事情。

TableViewController ,我添加了一个属性@property BOOL backPush; 到标题( .h )-file。 现在我需要从ViewController更改此变量。

ViewController ,我把它放在:

 #import "TableViewController" ... -(void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if(self.isMovingFromParentViewController) { if([self.navigationController.topViewController isKindOfClass:[TableViewController class]]) [((TableViewController*)self.navigationController.topViewController) setBackPush:YES]; } } 

在上面的代码中,当视图消失时(IE向前推,向后,关闭,等等),我正在检查我们是否正在消失,因为它已从父节点中删除。 如果是(当调用后退按钮时),我检查现在的顶级视图控制器是否属于TableViewController类,如果我们返回它也是如此。 然后我将属性backPush设置为YES 。 这是我们在ViewController唯一需要的东西。

现在,到TableViewController 。 我在你的行数旁边添加了一个计数器

 @interface TableViewController () { NSInteger _rows; int count; } 

这是为了跟踪稍后对viewDidLayoutSubviews进行了多少次调用。 我设置count = 0;viewDidLoad

现在到了魔术:

 -(void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; if((self.backPush && count == 0 && self.tableView.contentOffset.y == self.tableView.tableHeaderView.frame.size.height) || (self.backPush && count == 1 && self.tableView.contentOffset.y == 0)) { if(count == 0) count++; else { count = 0; self.backPush = NO; [self hideSearchBar]; } } else if((count == 0 || count == 1) || self.tableView.tableHeaderView.isFirstResponder) { count = 0; self.backPush = NO; } } 

第一个if语句需要以下任何一种情况:

  1. backPushYEScount0 ,并且searchBar已被隐藏。
  2. backPushYEScount1 ,并且searchBar可见。

如果1.为真,那么我们将count增加1.如果2.为真,那么1.已经发生了,我们现在知道我们处于第二轮viewDidLayout..当我们从VC回来时那个searchBar隐藏了(因为1.发生了)但现在没有隐藏。 它可能发生在超级方法或其他东西。 现在我们终于可以再次推出searchBar了。 我也重置计数并设置backPush回到NO

else if也很重要。 它检查count0还是1 ,或者searchBar是否显示键盘。 如果count到达此处时count为01 ,则表示第一个if语句失败,例如,searchBar未被隐藏,或者它已向远处滚动。

(当我想到它时,else-if应该检查backPush是否也是YES 。现在它重复设置这些变量)

如果你找到更好的方法,请告诉我!

我认为这个是简单的解决方案。 感谢Sti

提供一些想法来解决这个bug。

初始化变量var hideSearchBar = false

和viewDidLayoutSubviews内部添加此代码以保持相同的内容偏移量。

 if hideSearchBar == true { self.tableView.contentOffset = CGPointMake(0, self.tableView.tableHeaderView!.bounds.height - self.tableView.contentInset.top) } 

最后实现以下方法。

 override func scrollViewDidScroll(scrollView: UIScrollView) { if self.tableView.tableHeaderView!.bounds.height - self.tableView.contentInset.top == self.tableView.contentOffset.y && self.tableView.dragging == false { hideSearchBar = true } else if self.tableView.dragging == true {//Reset hiding process after user dragging hideSearchBar = false } } func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) if self.tableView.contentOffset.y + self.tableView.contentInset.top <= self.tableView.tableHeaderView!.bounds.height { self.tableView.contentOffset = CGPointMake(0, self.tableView.tableHeaderView!.bounds.height - self.tableView.contentInset.top) } } 

尝试设置TVC

  self.automaticallyAdjustsScrollViewInsets = NO 

这是由hidesBottomBarWhenPushed = YES引起的问题,如果取消选中Hide Bottom Bar On Push ,当VC返回TVC时,searchBar将不会出现。

在TableViewController.m中尝试这个:

 - (void)viewDidLayoutSubviews{ [super viewDidLayoutSubviews]; [self hideSearchBar]; } 

我无法解释为什么,但我知道如果hidesBottomBarWhenPushed = YES ,UITabBarController推送vc,当视图再次出现时, viewDidLayoutSubviews将被多次调用。 第一次子视图保持相同的位置,而第二次被调用,子视图将由于某种原因进行调整,以最原始的位置重新布局,这是非常奇怪的。 在viewDidLayoutSubviews自定义布局是否会在viewDidAppear之后阻止这种情况发生。

我的解决方案有点愚蠢。

将此方法添加到示例代码中。

 - (void)viewWillLayoutSubviews { [self hideSearchBar]; } 

似乎tableView将重绘其中的scrollView。

由于tableView重置了contentOffset,我做了一个自定义tableView的属性来保存搜索栏的隐藏状态。下面是代码。希望它有所帮助。

 // // TableViewController.m // SearchBarJump // // Created by Eyal Cohen on 3/9/14. // Copyright (c) 2014 Eyal. All rights reserved. // #import "TableViewController.h" @interface CustomTableView : UITableView @property (nonatomic, assign, getter = isSearchBarHidden)BOOL searchBarHidden; @end @implementation CustomTableView @synthesize searchBarHidden = _searchBarHidden; - (void)layoutSubviews { [super layoutSubviews]; if (self.isSearchBarHidden) { [self hideSearchBar:NO]; } } - (void)setSearchBarHidden:(BOOL)searchBarHidden { _searchBarHidden = searchBarHidden; if (_searchBarHidden && self.contentOffset.y != self.tableHeaderView.frame.size.height) { [self hideSearchBar:YES]; } } - (void)hideSearchBar:(BOOL)animated { // hide search bar [self setContentOffset:CGPointMake(0.0, self.tableHeaderView.frame.size.height) animated:animated]; } @end @interface TableViewController () { NSInteger _rows; } @property (nonatomic, weak) IBOutlet CustomTableView *mainTable; @end @implementation TableViewController @synthesize mainTable = _mainTable; - (id)initWithStyle:(UITableViewStyle)style { self = [super initWithStyle:style]; if (self) { // Custom initialization } return self; } - (void)viewDidLoad { [super viewDidLoad]; self.view = _mainTable; [_mainTable setDelegate:self]; [_mainTable setDataSource:self]; _rows = 3; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.mainTable setSearchBarHidden:YES]; } - (void)hideSearchBar { // hide search bar [_mainTable setContentOffset:CGPointMake(0.0, self.tableView.tableHeaderView.frame.size.height) animated:NO]; } - (IBAction)toggleCount:(UIBarButtonItem *)sender { if (_rows == 20) { _rows = 3; } else { _rows = 20; } [_mainTable reloadData]; } - (IBAction)hideBar:(UIBarButtonItem *)sender { [self hideSearchBar]; } #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Return the number of sections. return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. return _rows; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; // Configure the cell... cell.textLabel.text = @"cell"; return cell; } - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { [_mainTable setSearchBarHidden:NO]; } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { if (_mainTable.contentOffset.y == _mainTable.tableHeaderView.bounds.size.height) { [_mainTable setSearchBarHidden:YES]; } } @end 

UITableViewController始终在其viewDidAppear中修改其UITableviews内容偏移量,以确保其所有行都可见。 所以你的hacky方法在这里不起作用。

这个问题有几个解决方案。 我选择的那个如下所示

首先从故事板中删除该searchBar。

 @interface TableViewController(){
     NSInteger _rows;
 }

 @结束

 @implementation TableViewController

 - (id)initWithStyle:(UITableViewStyle)样式
 {
     self = [super initWithStyle:style];
     if(self){
         //自定义初始化
     }
    回归自我;
 }

 - (void)viewDidLoad
 {
     [super viewDidLoad];

     _rows = 4;  //为searchBar +1

 }

 - (无效)viewDidAppear:(BOOL)动画{
     [super viewDidAppear:animated];
 }

 - (void)hideSearchBar {
     //隐藏搜索栏
     [[self tableView] scrollToRowAtIndexPath:[NSIndexPath indexPathWithIndex:1] atScrollPosition:UITableViewScrollPositionTop animated:NO];
 }

 - (IBAction)toggleCount:(UIBarButtonItem *)sender {
     if(_rows == 20){
         _rows = 4;
     } else {
         _rows = 20;
     }
     [self.tableView reloadData];
 }

 - (IBAction)hideBar:(UIBarButtonItem *)sender {
     [self hideSearchBar];
 }

 #pragma mark  - 表视图数据源

 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
 {
     //返回部分的数量。
    返回1;
 }

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 {
     //返回部分中的行数。
     return _rows;
 }

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {

     if(indexPath.row == 0){
         UITableViewCell * cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
         UISearchBar * searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0,0,tableView.frame.size.width,44)];
         [cell addSubview:searchBar];
        返回细胞;
     }

     static NSString * CellIdentifier = @“Cell”;
     UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

     //配置单元格......
     cell.textLabel.text = @“cell”;

    返回细胞;
 }

 @结束

上述解决方案只是确保禁用自动滚动魔术。

如果您希望隐藏默认的searchBar,请覆盖UITableView,并在第一次初始加载tableview时调用hideSearchBar。

我修复了这个错误:

 @interface NTTableView : UITableView @end @implementation NTTableView -(void)setContentOffset:(CGPoint)contentOffset{ if (self.contentOffset.y==-20&& contentOffset.y==-64) { NSLog(@"iOS7 bug here, FML"); }else{ [super setContentOffset:contentOffset]; } } @end 

使用UISearchBar作为tableHeaderView修复了我有点类似的情况。 不确定这是否属于同一场景,但在视图出现时会隐藏搜索栏。 (不关心表格视图中的行数)

 - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO]; } 

edgesForExtendedLayout设置为[.top, .bottom] edgesForExtendedLayout [.top, .bottom]而不仅仅是TVC上的[.top, .bottom]修复了我的问题。

当然, automaticallyAdjustsScrollViewInsets设置为false
编辑:似乎它只有在tvc.tabBar是translucent才有效

作为一个奇怪的黑客,我只能建议在高度约为400的单元格的末尾添加一个空单元格

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. return _rows + 1; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; if(indexPath.row == _rows) { //cellEmpty - cell identifier in storyboard cell = [tableView dequeueReusableCellWithIdentifier:@"cellEmpty" forIndexPath:indexPath]; } else { cell.textLabel.text = @"cell"; } // Configure the cell... return cell; } -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if(indexPath.row == _rows) { return 400; } else { return 44; } } 

你的输出文件

https://github.com/iDevAndroid/SearchBarJump

只需使用此代码就不要为此做复杂

 -(void)viewDidDisappear:(BOOL)animated{ [self.tableView setContentInset:UIEdgeInsetsMake(-0.3, 0, 0, 0)]; [super viewDidAppear:animated]; } 

这是一个问题,如果你设置UIEdgeInsetsMake(0,0,0,0)searchBar跳转为原始模式