我的UI结构如下:
UITabBarController
( TBC ) - > UINavigationController
( NC ) - > UITableViewController
( TVC )
(为了简单示例,假设 TBC 在其viewControllers
阵列上只有一个控制器 - NC )
我的 TVC 有UISearchBar
作为其表格标题,当 TVC 出现时,我隐藏 NC 下方的搜索栏导航栏通过设置表视图内容偏移量。
当用户点按 TVC 中的单元格时,会推送另一个视图控制器( VC ),并使用VC.hidesBottomBarWhenPushed = YES;
隐藏标签栏
现在有一种非常讨厌的行为,我不知道如何解决:
当用户点击 VC 中的后退按钮返回 TVC 时,即使隐藏(在导航栏下方)之前搜索栏也会跳转显示VC 被推了。
仅当 TVC 没有足够的行来填充屏幕时才会出现此效果,如果屏幕上有某个位置,它就像搜索栏一样强制自己可见。但它真的看起来很糟糕和马车。
我上传了一个显示问题的simple project,它与我在问题中描述的结构相同 为方便起见,我添加了两个小节按钮,“隐藏栏”按钮为您隐藏搜索栏,“切换计数”按钮切换表格视图行计数,以证明只有少数项目才会出现问题。
答案 0 :(得分:7)
好的..在我看来,你已经偶然发现了一个错误。它应该通过apples bugreporter(here)报告。
我做了一个简单易懂的工作,但请记住, 是一种解决方法。这将有效,但如果您有/向tableView添加其他控件,则可能需要查看它。它应该是安全的(不是随意的),并且它不是最难处理的,所以我认为在一个版本中使用它是好的。我已经使用修复程序here 上传了相同的项目,您可以继续下载它,您可能已经了解我已完成的工作。我将解释(非常详细)我在这里实际思考和完成的内容,以防下载链接在将来死亡:
思路:
正如simalone所说,问题是当hidesBottomBarWhenPushed
设置为YES
时,它会调用额外的viewDidLayoutSubviews
,以某种方式重置您当前的状态。我们需要覆盖viewDidLayoutSubviews
,并检查我们是否正在布置子视图,因为我们来自ViewController
,或者它是否只是常规电话。当我们确定调用确实是因为我们从ViewController
返回时,我们需要隐藏搜索栏(仅当它被隐藏之前)。
当我们从ViewController
返回时,会在viewDidLayoutSubviews
中对TableViewController
进行三次调用。我猜第一个是tableView
,而第二个电话似乎是'(或者来自)tabBar。第二个是移动searchBar
的人。我不知道第三个电话是什么,但我们可以忽略它。
所以现在我们需要在viewDidLayoutSubviews
内检查三件事:我们需要检查一下是否从ViewController
返回,我们需要在推送之前检查searchBar是否被隐藏(如果是应隐藏现在),我们需要检查它是否对此方法进行第二次调用。
首先要做的事情。
在TableViewController
中,我在标题(@property BOOL backPush;
) - 文件中添加了一个属性.h
。现在我需要从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];
}
}
在上面的代码中,当视图消失时(I.E向前,向后,关闭等等),我会检查我们是否正在消失,因为它已从父母中移除。如果是(当调用后退按钮时),我会检查现在 - 当前顶视图控制器是否属于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
,搜索栏已隐藏。backPush
为YES
,count
为1
,搜索栏可见。如果1.为真,那么我们将count
增加1。
如果2.为真,那么1.已经发生了,我们现在知道当我们从 VC 回来并且searchBar viewDidLayout..的第二轮> WAS 隐藏(因为1.发生了)但现在并未隐藏。它可能发生在超级方法或其他东西。
现在我们终于可以再次推出searchBar了。我还重置了count并将backPush设置回NO
。
else if
也非常重要。它会检查count
是0
还是1
,或者搜索栏是否显示键盘。如果count到达此处时为0
或1
,则表示第一个if语句失败,例如,searchBar未被隐藏,或者它已向远处滚动。
(当我想到它时,else-if应该检查backPush
是否也是YES
。现在它重复设置这些变量)
如果你找到更好的方法,请告诉我!
答案 1 :(得分:2)
我认为这是一个简单的解决方案。谢谢 Sti
提供一些想法来解决这个错误。
初始化变量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)
}
}
答案 2 :(得分:1)
尝试设置TVC
self.automaticallyAdjustsScrollViewInsets = NO
答案 3 :(得分:0)
这是由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
发生这种情况。
答案 4 :(得分:0)
UITableViewController始终在其viewDidAppear中修改其UITableviews内容偏移量,以确保其所有行都可见。所以你的hacky方法在这里不起作用。
这个问题有几个解决方案。我选择的那个如下所示
首先从故事板中删除该搜索栏。
@interface TableViewController () { NSInteger _rows; } @end @implementation TableViewController - (id)initWithStyle:(UITableViewStyle)style { self = [super initWithStyle:style]; if (self) { // Custom initialization } return self; } - (void)viewDidLoad { [super viewDidLoad]; _rows = 4; // +1 for searchBar } -(void)viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; } - (void)hideSearchBar { // hide search bar [[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 - 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 { 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]; return cell; } static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; // Configure the cell... cell.textLabel.text = @"cell"; return cell; } @end
上述解决方案只是确保禁用自动滚动魔法。
如果您希望隐藏默认的searchBar,请覆盖UITableView,并在首次加载tableview时调用hideSearchBar。
答案 5 :(得分:0)
我的解决方案有点愚蠢。
将此方法添加到示例代码中。
- (void)viewWillLayoutSubviews
{
[self hideSearchBar];
}
似乎tableView会重绘其中的scrollView。
答案 6 :(得分:0)
由于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
答案 7 :(得分:0)
我修复了这个错误:
@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
答案 8 :(得分:0)
修复了与UISearchBar
tableHeaderView
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
}
类似的情况。不确定这是否属于同一场景,但在视图出现时会隐藏搜索栏。 (不关心表格视图中的行数)
bookings:size
答案 9 :(得分:0)
将edgesForExtendedLayout
设置为[.top, .bottom]
,而不是仅仅.top
TVC 为我解决问题。
当然,automaticallyAdjustsScrollViewInsets
设置为false
编辑:似乎只有在tvc.tabBar为translucent
答案 10 :(得分:-1)
作为一个奇怪的黑客,我只能建议在高度约为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;
}
}
答案 11 :(得分:-1)
您的输出文件
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在原始模式下跳转,这是一个问题