I have a search bar implemented and it 'sticks' to the tableView. Now, after the tableView starts scrolling, the searchBar does not receive touches and become the first responder, instead, the cell behind it does and navigates to the next view. What can I do to make the searchBar receive touches?
Code for keeping it static:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
UISearchBar *searchBar = self.search;
[[self.tableView.tableHeaderView superview] bringSubviewToFront:self.tableView.tableHeaderView];
CGRect searchBarFrame = searchBar.frame;
if (self.inSearchMode)
{
searchBarFrame.origin.y = 0;
}
else
{
searchBarFrame.origin.y = MAX(0, scrollView.contentOffset.y + scrollView.contentInset.top);
}
self.search.frame = searchBarFrame;
}
If you think about it, the table header frame will be outside the table bounds when you scroll.
Try to add it as a subview to the tableView directly and set its frame relative to tableView bounds to keep it sticky.
Related
Using storyboard, I have placed an imageView as my tableView's headerView inside a ViewController.
This is how my storyboard is set up:
Depending on what data the user is viewing, the viewController will either show or hide the headerView. My question is, that when the headerView is visible and the user drags down on the tableView, how can I have the imageView stick to both the navigationBar and the tableView as it resizes to cover the space in between?
This is what it currently does:
But this is what I'm going for:
Any help would be greatly appreciated. I've looked at parallax libraries, but none support sectionTitles, and I'm not necessarily going for the parallax effect either. When the user scrolls up, I want it to bounce back to the regularView and not hide the headerView. Thanks!
UPDATE:
I have followed the advice posted by Dany below and have done the
following:
-(void)scrollViewDidScroll:(UIScrollView*)scrollView {
CGRect initialFrame = CGRectMake(0, 0, 320, 160);
if (scrollView.contentOffset.y < 0) {
initialFrame.size.height =! scrollView.contentOffset.y;
childHeaderView.frame = initialFrame;
} }
childHeaderView is an imageView and for some reason when I drag down,
the image moves up (like half of it behind the navBar) and doesn't return. Any advice would be
greatly appreciated!! Thanks!
I recently posted a blog post about accomplishing this using constraints which might help, turns out it was quite straight forward.
Here is the link: Creating parallax effect on UIScrollView using constraints
First of all you should remove the UIImageView from the header and add it as a simple UIImageView on top of the UITableView then since UITableViewDelegate protocol conforms to UIScrollViewDelegate protocol you can implement the scrollViewDidScroll: method to check when the tableView is scrolling down and has a bouncing effect. something like this:
-(void)someInitMethod {
initialFrame = yourHeaderView.frame;
}
-(void)scrollViewDidScroll:(UIScrollView*)scrollView {
if(scrollView.contentOffset.y < 0) {
initialFrame.size.height -= scrollView.contentOffset.y;
yourHeaderView.frame = initialFrame;
}
}
Also make sure you set the proper contentMode for your UIImageView. Also I think this implementation will create a bouncing effect but I'm not sure because I can't test it right now but I think this is a good start point for you.
This is how I achieved it, in my case I was using a map view up the top:
Create a View Controller in storyboard.
Add a Table View and set the constraints to 0 from all sides.
Add a Map View (or whatever view) below the Table View so that it will get rendered over the top. It will look like it is overlapping.
Add constraints to the top left and right.
In the view controller viewDidLoad add the following: tableView.contentInset = UIEdgeInsetsMake(200, 0, 0, 0) where 200 is the height of the View. This will push the contents of the table view downwards.
In the view controller add the following code, which resizes the view based on the scrolling:
func scrollViewDidScroll(scrollView: UIScrollView) {
var scrollOffset = scrollView.contentOffset.y
var headerFrame = mapView.frame
if (scrollOffset < 0) {
// Adjust map
headerFrame = CGRect(x: mapView.frame.origin.x,
y: mapView.frame.origin.y,
width: mapView.frame.size.width,
height: -scrollOffset)
} else {
// Adjust map
headerFrame = CGRect(x: mapView.frame.origin.x,
y: mapView.frame.origin.y,
width: mapView.frame.size.width,
height: 0)
}
mapView.frame = headerFrame
}
If I could set contentInset from the storyboard it would be even more pretty
Please have a look at this https://github.com/matteogobbi/MGSpotyViewController which implements the same effect as per your requirement.
The earlier solutions on this page gave me some trouble when I needed this to work along with section titles and index bar, so I came up with the following alternative myself. Please note; I don't use autolayout in my project and I've only tested this on iOS9+;
In your project's storyboard:
Create a UITableView within a UIViewController (or try it with a UITableViewController).
Drop a UIView at the top (but within) the UITableView, so it becomes a table header above the first cell.
Give this header view a desired height (like 200px for example) and set the background color to "Clear Color". The Clear Color is important, the view needs to be see-through.
Drop a 2nd UIView within the table header UIView and make it the same size as it's parent. This will be the actual header, so feel free to give it any color, setup an image view or other content.
Connect this 2nd UIView to your UIViewController IBOutlet, I named it "headerView" in my case.
Next, go to your UIViewController.m:
- (void)viewDidLoad
{
[super viewDidLoad];
// Remove view from table header and place it in the background instead.
[self.headerView removeFromSuperview];
UIView *backgroundView = [UIView new];
[backgroundView addSubview:self.headerView];
self.tableView.backgroundView = backgroundView;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
/* Set initialScrollOffset ivar to start offset, because in my case
the scroll offset was affected by the statusbar + navigation bar heights
and the view controller's "extend edges under top bars" option. */
initialScrollOffset = self.tableView.contentOffset.y;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
/* Modify headerView height only if the table content gets pulled
beyond initial offset. */
if (scrollView.contentOffset.y < initialScrollOffset) {
CGRect frame = self.headerView.frame;
frame.size.height = self.tableView.tableHeaderView.frame.size.height + -scrollView.contentOffset.y;
self.headerView.frame = frame;
}
}
I needed this implementation only for a stretching header with background color and labels. It should be easy to add a UIImageView to this header though.
Also, steps 1 to 5 are completely optional of course. You can programmatically create your header view or use a XIB instead. As long as you make sure the table has a Clear Colored header view set with the same height as your desired header because this serves as a spacer to keep your cells and section titles in line.
EDIT:
I found an even cleaner way to accomplish this;
Build up your table header in interface builder as described above: 1 UIView as container with a 2nd UIView embedded within.
Skip the viewDidLoad code above, there is no need to pull the UIView out of it's container and we won't need to set it as a table background.
Change the scrollViewDidScroll: method to this:
UIViewController.m:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView.contentOffset.y < initialScrollOffset) {
CGRect frame = self.headerView.frame;
frame.size.height = self.tableView.tableHeaderView.frame.size.height - scrollView.contentOffset.y;
frame.origin.y = self.tableView.tableHeaderView.frame.origin.y + scrollView.contentOffset.y;
self.headerView.frame = frame;
}
}
That's it. Only visual difference from the other solution is that the contents will now scroll up along with the rest of the cells instead of being overlapped by them.
I don't know, if this would help you or not ..
Set your scroll delegate to self.
and then implement this:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
float scrollViewHeight = scrollView.frame.size.height;
float scrollContentSizeHeight = scrollView.contentSize.height;
float scrollOffset = scrollView.contentOffset.y;
if (scrollOffset == 0)
{
// then we are at the top
}
else if (scrollOffset + scrollViewHeight == scrollContentSizeHeight)
{
// then we are at the end
// Do what you need here
}
}
I want a tableview that starts offscreen and can scroll on-screen, reach the top, and keep scrolling. I've made a visual of the desired interaction below.
I've tried two things, and neither work exactly like I need.
The first thing I did was put the tableview in a scrollview, and move the scrollview when panning is detected on the tableview. This blocks touches in the tableview, and even if I could detect when the tableview hit the top of the screen, I'm not sure how I would continue scrolling.
The second thing I tried was to set the content size of the scrollview to the height of the tableview. This lets the tableview scroll, but I only seem to be able to receive touches in the initial small rectangle labeled "List Item 1". As the tableview scrolls, I can't grab the middle and scroll it anymore.
What's the best way to build this interaction? Edit: A map surrounds this bottom view to the left, right, and mostly top. When the bottom view is pulled up, the map is visible to the left and right.
1.)
2.)
3.) (and this keeps scrolling for as many items are as in the list.)
I guess you want something like this:
or this:
I laid out my table view over my map view. I set the table view's contentInset and contentOffset like this:
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.rowHeight = 44;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.tableView.contentInset = (UIEdgeInsets){ .top = self.view.bounds.size.height - self.tableView.rowHeight };
self.tableView.contentOffset = CGPointMake(0, -self.tableView.contentInset.top);
}
Note that, although the default row height is 44, tableView.rowHeight return -1 unless you explicitly set it. (Setting it to 44 in the storyboard doesn't change this.)
I used a subclass of UITableView in which I did two things:
I explicitly set self.backgroundColor = [UIColor clearColor]. I found that setting the background color to clear in the storyboard didn't work.
I overrode pointInside:withEvent::
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
return point.y >= 0 && [super pointInside:point withEvent:event];
}
Note that you don't care about contentInset here. The table view's contentOffset.y (which is the same as its bounds.origin.y) is set to a negative number when its top content inset is exposed. It's set to 0 when the top of item 0 is at the top edge of the table view, which isn't the case when the item as at the bottom edge of the screen.
Another thing you might want is to prevent the table from stopping half-on the screen. If the user drags item 0 halfway up the screen, you want the table to scroll so item 0 is all the way at the top of the screen (if there are sufficient items), and if the user drags item 0 halfway down the screen, you want the table to scroll so just item 0 is showing.
I did that by making my view controller act as the table view's delegate and implementing this delegate method, inherited from UIScrollViewDelegate:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
CGFloat yMin = -self.tableView.contentInset.top;
CGFloat yMax = MIN(0, self.tableView.contentSize.height - self.tableView.bounds.size.height);
if (targetContentOffset->y < yMax) {
if (velocity.y < 0) {
targetContentOffset->y = yMin;
} else {
targetContentOffset->y = yMax;
}
}
}
That method is carefully written so that it works for tables too short to fill the screen vertically, and for tables that can fill the screen vertically.
I've uploaded my test project here: https://github.com/mayoff/tableView-over-mapview
Update for side-by-side tables
I don't think side-by-side tables is going to be a good user interface. I think it's going to be confusing. But here's how you do it.
The view hierarchy looks like this:
Root view
MKMapView
MyScrollView
ScrollContentView
MyTableView for first table
MyTableView for second table
MyTableView for third table
etc.
The map view and the scroll view have the same frames. The scroll view handles the sideways scrolling and each table view is independently scrollable vertically.
Since the scroll view should only capture touches that land in one of the table views, it needs a custom hitTest:withEvent: that returns nil for touches outside any of the table views:
#implementation MyScrollView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *hitView = [super hitTest:point withEvent:event];
return hitView == self ? nil : hitView;
}
#end
But this won't actually do the job, because (in my implementation) the scroll view has just one big subview, the ScrollContentView. So we need to do the same thing in ScrollContentView:
#implementation ScrollContentView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *hitView = [super hitTest:point withEvent:event];
return hitView == self ? nil : hitView;
}
That's sufficient to pass touches down to the map view if they land outside of the tables.
I also use ScrollContentView to lay out the tables and set the scroll view's content size:
- (void)layoutSubviews {
[super layoutSubviews];
// Layout of subviews horizontally:
// [gutter/2][gutter][subview][gutter][subview][gutter][subview][gutter][gutter/2]
// where 3 * gutter + subview = width of superview
CGSize superSize = self.superview.bounds.size;
CGFloat x = kGutterWidth * 3 / 2;
CGFloat subWidth = superSize.width - kGutterWidth * 3;
for (UITableView *subview in self.subviews) {
subview.frame = CGRectMake(x, 0, subWidth, superSize.height);
x += subWidth + kGutterWidth;
CGFloat topInset = superSize.height - subview.rowHeight;
subview.contentInset = (UIEdgeInsets){ .top = topInset };
subview.contentOffset = CGPointMake(0, -topInset);
}
x += kGutterWidth / 2;
self.frame = CGRectMake(0, 0, x, superSize.height);
((UIScrollView *)self.superview).contentSize = self.bounds.size;
_pageWidth = subWidth + kGutterWidth;
}
I also made my view controller be the scroll view's delegate, and implemented a delegate method to force the scroll view to stop on “page” (table) boundaries:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
CGFloat pageWidth = contentView.pageWidth;
// Force scroll view to stop on a page boundary.
CGFloat pageNumber = targetContentOffset->x / pageWidth;
if (velocity.x < 0) {
pageNumber = floor(pageNumber);
} else {
pageNumber = ceil(pageNumber);
}
pageNumber = MAX(0, MIN(pageNumber, contentView.subviews.count - 1));
targetContentOffset->x = pageNumber * pageWidth;
}
The result:
I've updated the git repository with this version.
You ought to be able to do this pretty easily by setting your table view’s top contentInset to something high (as sha suggested in the comments) and then making your UITableView a subclass so you can override -pointInside:withEvent:. Using that and the current contentOffset, you can determine whether the incoming event is inside the area you want to be scrollable, and return YES or NO accordingly; if you return NO, then the touch should fall through to the map view as intended.
Why not change this completely. You said you have a map "underneath" the tableview. So when scrolled up the map will be hidden over by the table view. I presume when you scroll down again the map will be revealed?
You should be able to do this by using the UITableView header. Either a section header or a table view header. They behave slightly differently upon scrolling.
I'd maybe do it this way...
Use a table view header on the table. In this header you place your map view.
By default this will be pinned to the top of the table so if you scroll the table up then the map will slide off the top of the screen with it.
However, if you then intercept the scroll view delegate method - (void)scrollViewDidScroll:(UIScrollView *)scrollView; then you can work out if the table is being scrolled upwards and offset the map view so it stays where it is.
i.e. if the table is scrolled to (0, 10) then offset the map to (0, -10) so it looks like it hasn't moved.
This will give you the scroll in and out feature of the tableview and keep the map in view and responding to touches.
Using storyboard, I have placed an imageView as my tableView's headerView inside a ViewController.
This is how my storyboard is set up:
Depending on what data the user is viewing, the viewController will either show or hide the headerView. My question is, that when the headerView is visible and the user drags down on the tableView, how can I have the imageView stick to both the navigationBar and the tableView as it resizes to cover the space in between?
This is what it currently does:
But this is what I'm going for:
Any help would be greatly appreciated. I've looked at parallax libraries, but none support sectionTitles, and I'm not necessarily going for the parallax effect either. When the user scrolls up, I want it to bounce back to the regularView and not hide the headerView. Thanks!
UPDATE:
I have followed the advice posted by Dany below and have done the
following:
-(void)scrollViewDidScroll:(UIScrollView*)scrollView {
CGRect initialFrame = CGRectMake(0, 0, 320, 160);
if (scrollView.contentOffset.y < 0) {
initialFrame.size.height =! scrollView.contentOffset.y;
childHeaderView.frame = initialFrame;
} }
childHeaderView is an imageView and for some reason when I drag down,
the image moves up (like half of it behind the navBar) and doesn't return. Any advice would be
greatly appreciated!! Thanks!
I recently posted a blog post about accomplishing this using constraints which might help, turns out it was quite straight forward.
Here is the link: Creating parallax effect on UIScrollView using constraints
First of all you should remove the UIImageView from the header and add it as a simple UIImageView on top of the UITableView then since UITableViewDelegate protocol conforms to UIScrollViewDelegate protocol you can implement the scrollViewDidScroll: method to check when the tableView is scrolling down and has a bouncing effect. something like this:
-(void)someInitMethod {
initialFrame = yourHeaderView.frame;
}
-(void)scrollViewDidScroll:(UIScrollView*)scrollView {
if(scrollView.contentOffset.y < 0) {
initialFrame.size.height -= scrollView.contentOffset.y;
yourHeaderView.frame = initialFrame;
}
}
Also make sure you set the proper contentMode for your UIImageView. Also I think this implementation will create a bouncing effect but I'm not sure because I can't test it right now but I think this is a good start point for you.
This is how I achieved it, in my case I was using a map view up the top:
Create a View Controller in storyboard.
Add a Table View and set the constraints to 0 from all sides.
Add a Map View (or whatever view) below the Table View so that it will get rendered over the top. It will look like it is overlapping.
Add constraints to the top left and right.
In the view controller viewDidLoad add the following: tableView.contentInset = UIEdgeInsetsMake(200, 0, 0, 0) where 200 is the height of the View. This will push the contents of the table view downwards.
In the view controller add the following code, which resizes the view based on the scrolling:
func scrollViewDidScroll(scrollView: UIScrollView) {
var scrollOffset = scrollView.contentOffset.y
var headerFrame = mapView.frame
if (scrollOffset < 0) {
// Adjust map
headerFrame = CGRect(x: mapView.frame.origin.x,
y: mapView.frame.origin.y,
width: mapView.frame.size.width,
height: -scrollOffset)
} else {
// Adjust map
headerFrame = CGRect(x: mapView.frame.origin.x,
y: mapView.frame.origin.y,
width: mapView.frame.size.width,
height: 0)
}
mapView.frame = headerFrame
}
If I could set contentInset from the storyboard it would be even more pretty
Please have a look at this https://github.com/matteogobbi/MGSpotyViewController which implements the same effect as per your requirement.
The earlier solutions on this page gave me some trouble when I needed this to work along with section titles and index bar, so I came up with the following alternative myself. Please note; I don't use autolayout in my project and I've only tested this on iOS9+;
In your project's storyboard:
Create a UITableView within a UIViewController (or try it with a UITableViewController).
Drop a UIView at the top (but within) the UITableView, so it becomes a table header above the first cell.
Give this header view a desired height (like 200px for example) and set the background color to "Clear Color". The Clear Color is important, the view needs to be see-through.
Drop a 2nd UIView within the table header UIView and make it the same size as it's parent. This will be the actual header, so feel free to give it any color, setup an image view or other content.
Connect this 2nd UIView to your UIViewController IBOutlet, I named it "headerView" in my case.
Next, go to your UIViewController.m:
- (void)viewDidLoad
{
[super viewDidLoad];
// Remove view from table header and place it in the background instead.
[self.headerView removeFromSuperview];
UIView *backgroundView = [UIView new];
[backgroundView addSubview:self.headerView];
self.tableView.backgroundView = backgroundView;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
/* Set initialScrollOffset ivar to start offset, because in my case
the scroll offset was affected by the statusbar + navigation bar heights
and the view controller's "extend edges under top bars" option. */
initialScrollOffset = self.tableView.contentOffset.y;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
/* Modify headerView height only if the table content gets pulled
beyond initial offset. */
if (scrollView.contentOffset.y < initialScrollOffset) {
CGRect frame = self.headerView.frame;
frame.size.height = self.tableView.tableHeaderView.frame.size.height + -scrollView.contentOffset.y;
self.headerView.frame = frame;
}
}
I needed this implementation only for a stretching header with background color and labels. It should be easy to add a UIImageView to this header though.
Also, steps 1 to 5 are completely optional of course. You can programmatically create your header view or use a XIB instead. As long as you make sure the table has a Clear Colored header view set with the same height as your desired header because this serves as a spacer to keep your cells and section titles in line.
EDIT:
I found an even cleaner way to accomplish this;
Build up your table header in interface builder as described above: 1 UIView as container with a 2nd UIView embedded within.
Skip the viewDidLoad code above, there is no need to pull the UIView out of it's container and we won't need to set it as a table background.
Change the scrollViewDidScroll: method to this:
UIViewController.m:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView.contentOffset.y < initialScrollOffset) {
CGRect frame = self.headerView.frame;
frame.size.height = self.tableView.tableHeaderView.frame.size.height - scrollView.contentOffset.y;
frame.origin.y = self.tableView.tableHeaderView.frame.origin.y + scrollView.contentOffset.y;
self.headerView.frame = frame;
}
}
That's it. Only visual difference from the other solution is that the contents will now scroll up along with the rest of the cells instead of being overlapped by them.
I don't know, if this would help you or not ..
Set your scroll delegate to self.
and then implement this:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
float scrollViewHeight = scrollView.frame.size.height;
float scrollContentSizeHeight = scrollView.contentSize.height;
float scrollOffset = scrollView.contentOffset.y;
if (scrollOffset == 0)
{
// then we are at the top
}
else if (scrollOffset + scrollViewHeight == scrollContentSizeHeight)
{
// then we are at the end
// Do what you need here
}
}
I have a overlay UIView above a UITableview. When I scroll the UITableview, I want the overlay UIView to move at the same speed as UITableview scroll,just as the top menu of the facebook app.
Any suggestions?
I try to change the overlay uiview's frame in uitableview's scroll delegate.something like:
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
self.lastOffsetY = scrollView.contentOffset.y;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat offset = self.lastOffsetOfY - scrollView.contentOffset.y;
CGRect frame = self.overlayview.frame;
frame.origin.y += offset;
self.overlayview.frame = frame;
self.lastOffsetOfY = scrollView.contentOffset.y;
}
just use change of contentoffset value. but the overlay uiview doesn't move the same as the uitableview scroll.
If you just want that UIView to stick to the top of the screen at all times, independent of the tableview you just need to add the UIView to your controller's view instead of adding it to the tableview.
In your XIB, if you're using one, You should have something like
VIEW
UITableView
UIView
Instead of what you probably have:
VIEW
UITableView
UIView
If you're trying to accomplish an overlay similar to the Facebook app, it's going to be more efficient to add the overlay to the superview that houses your UITableView/ScollView. This way you won't need to write a bunch of code that needs to execute every time your user scrolls.
//in your View Controller:
UITableView *table = [[[UITableview alloc] init] autorelease];
CGRect frame = CGRectMake (tableOriginX, tableOriginY, width, height);
UIView *overlay = [[[UIView alloc] initWithDesieredFrame: frame] autorelease];
This way the view never moves, but gives the illusion of always existing at the top of the TableView. If, like facebook, you wish to dismiss the view, you can use the TableView's internal gesture recognizers to detect a flick (like facebook) that will dismiss or summon the overlay.
//Something like:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
if (velocity.y > 0)
{
[self hideButtonPannelData];
}
if (velocity.y < -0.8)
{
[self revealButtonPannelData];
}
I want to get the behavior like this:
I have a UISearchBar, which is a table header view of my tableview. When scrolling the table, the search bar does indeed move, but if you scroll above the boundaries of the table, the search bar never stops touching the navigation bar.
I found a good answer here - Locking a UISearchBar to the top of a UITableView like Game Center
But it not works on iOS 6 - manipulations with table view header frame don't work
What can be the reason of this?
I found a solution, which works on iOS 6 and lower
Make a subclass of UITableView and override layoutSubviews method
- (void)layoutSubviews
{
[super layoutSubviews];
CGRect rect = self.tableHeaderView.frame;
rect.origin.y = MIN(0, self.contentOffset.y);
self.tableHeaderView.frame = rect;
}
If you use the following:
[_tableView setTableHeaderView:_searchBar];
When you scroll the table view beyond the first row, the search bar should also disappear rather than sticking to the top of the view.
Without seeing your code, I can only assume that perhaps you have added the UISearchBar as your section header rather than the table header?
That because iOS6 sdk not update when scrolling, maybe same optimize. so need to call tableview layoutSubviews when scroll.
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
UISearchBar *searchBar = searchDisplayController.searchBar;
CGRect rect = searchBar.frame;
rect.origin.y = MIN(0, scrollView.contentOffset.y);
[scrollView layoutSubviews];
searchBar.frame = rect;
}