如果推送控制器隐藏标签栏,UISearchBar会跳转
我的UI结构如下:
UITabBarController
( TBC ) – > UINavigationController
( NC ) – > UITableViewController
( TVC )
(为了简化示例,我们可以说TBC在其viewControllers
数组上只有一个控制器viewControllers
)
我的TVC将UISearchBar
作为其表格标题,当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语句需要以下任何一种情况:
-
backPush
为YES
,count
为0
,并且searchBar已被隐藏。 -
backPush
为YES
,count
为1
,并且searchBar可见。
如果1.为真,那么我们将count
增加1.如果2.为真,那么1.已经发生了,我们现在知道我们处于第二轮viewDidLayout..
当我们从VC回来时那个searchBar隐藏了(因为1.发生了)但现在没有隐藏。 它可能发生在超级方法或其他东西。 现在我们终于可以再次推出searchBar了。 我也重置计数并设置backPush回到NO
。
else if
也很重要。 它检查count
是0
还是1
,或者searchBar是否显示键盘。 如果count到达此处时count为0
或1
,则表示第一个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跳转为原始模式