我使用界面生成器创建了一个表视图,在该视图中添加了库的搜索栏和搜索显示控制器以添加搜索功能。但是,IB对其进行了设置,以便首次显示视图时,该条在屏幕顶部可见。
我想知道默认情况下如何隐藏搜索栏,但仍可以在表格视图中滚动(有关示例,请参阅Apple的Mail应用程序)。我已经打过电话scrollRectToVisible:animated:
中viewDidLoad
滚动表视图下来,但无济于事。默认情况下,隐藏搜索栏的首选方法是什么?
Answers:
首先,确保将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没有指向有效的行(即,如果表视图为空)将引发异常)。
contentOffset
如果您使用复杂的视图控制器布局,则使用任何值进行设置都会中断。我不推荐。
不要将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];
}
viewWillAppear
不是一个好主意,因为它会在您每次导航回到视图时都运行。这意味着您的表视图将逐渐缩小。令人讨厌的错误!
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];
viewDidAppear:
而不是实施动画,那么我已经成功完成了此过程而无需动画viewDidLoad
。
此解决方案有很多答案,但是对我来说,没有一个很好的解决方案。
这很完美。没有动画,并且完成-viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.contentOffset = CGPointMake(0, self.searchBar.frame.size.height - self.tableView.contentOffset.y);
}
注意:
代码假定您具有searchBar
@property
链接到搜索栏的。如果没有,您可以self.searchDisplayController.searchBar
改用
-viewWillAppear
不工作..是否得到当标签控制器切换到视图叫什么?
对于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)
我的目标是在加载视图控制器时隐藏添加到情节提要中纯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()
当没有足够的行来填充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真正有效的唯一解决方法。我想知道是否有更整洁的解决方案。
以上都不对我有用,所以以防万一有人遇到同样的问题。
我已在iOS7的分组表上searchBar
设置为tableHeaderView
。在最初,viewDidLoad
我必须tableView.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
落后于toolBar
这工作: tableView.setContentOffset(CGPointMake(0, -20)
似乎不合逻辑,但只有-20向上移动到正确位置
CGRectGetHeight(searchBar.bounds)
?
ContentOffset
解决方案均不起作用
请注意,如果表视图中没有数据,则接受的答案将崩溃。并将其添加到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)];
}
老实说,没有一个答案能真正解决这个问题(对我来说)。如果您的表格视图没有行,或者行高不同,那么这些答案就不够了。
唯一有效的方法:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.tableView.contentOffset = (CGPoint){.y = self.tableView.contentOffset.y + self.searchController.searchBar.frame.size.height};
}
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
。
我发现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];
}
希望这可以帮助 :-)
这个问题的其他答案对我来说根本不起作用,或者当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
)。如果是,它只是向下滚动searchBar的高度。如果searchBar不可见(请在中查看较大的项列表tableView
),则它将不会尝试滚动tableView
,因为当您从嵌套订单项返回时,这会弄乱位置。
旁注
我建议将此代码放在单独的方法中,以确保单项职责,并使您可以在代码中随时调用它。
如果您的表格始终至少有一行,只需滚动到表格的第一行,搜索栏就会自动隐藏。
let firstIndexPath = NSIndexPath(forRow: 0, inSection: 0)
self.tableView.selectRowAtIndexPath(firstIndexPath,动画:false,scrollPosition:.Top)
如果将上面的代码放在viewDidLoad上,则将引发错误,因为tableView尚未加载,因此必须将其放在viewDidAppear中因为此时tableView已经加载。
如果放在viewDidAppear上,则每次打开tableView时,它将滚动到顶部。
如果tableView保持打开状态,例如当它是UITabBar View Controller或执行segue然后返回时,也许您不希望这种行为。如果只希望它在初始加载时滚动到顶部,则可以创建一个变量来检查它是否是初始加载,以便它只滚动一次到顶部。
首先在视图控制器类中定义一个名为isInitialLoad的变量,并将其设置为等于“ true”:
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
}
我尝试设置内容偏移量和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)
}
}
这就像一个魅力一样.content offset设置用于平滑滚动目的
迅捷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)
}
我有类似的问题。我发现解决此问题的唯一方法是在UITableView contentOffset属性上使用键值观察器。
经过一些调试后,我意识到即使表视图内容的大小小于表视图的大小,也会出现问题。我在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"];
}