UITableView contentSize wrong when using UISearchBar - ios

UITableView is reporting a bigger contentSize than expected when using a UISearchBar. With zero cells, the expected content height would be zero. Instead, the following code outputs 612 in iPhone 4-inch running iOS 7.
#implementation HPViewController {
UITableView *_tableView;
UISearchBar *_searchBar;
UISearchDisplayController *_searchController;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_tableView = [[UITableView alloc] initWithFrame:self.view.bounds];
_tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:_tableView];
_searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
_searchController = [[UISearchDisplayController alloc] initWithSearchBar:_searchBar contentsController:self];
_searchController.delegate = self;
_searchController.searchResultsDataSource = self;
_tableView.tableHeaderView = _searchBar;
}
- (void)viewDidLayoutSubviews
{
CGSize contentSize = _tableView.contentSize;
NSLog(#"%f", contentSize.height); // 612.000000
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 0; }
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { return nil; };
#end
Commenting the line that sets the header view makes the code output 0, as expected.
Also, if I assign an empty UIView as the header, the contentSize will be correct and match the height of the header. The problem only happens with UISearchBar.
Is there any way around this? Am I doing something wrong?

Placing the UISearchBar inside a container UIView mostly fixes the problem.
- (void)viewDidLoad
{
[super viewDidLoad];
_tableView = [[UITableView alloc] initWithFrame:self.view.bounds];
_tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:_tableView];
UIView *searchBarContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
_searchBar = [[UISearchBar alloc] initWithFrame:searchBarContainer.bounds];
[searchBarContainer addSubview:_searchBar];
_searchController = [[UISearchDisplayController alloc] initWithSearchBar:_searchBar contentsController:self];
_searchController.delegate = self;
_searchController.searchResultsDataSource = self;
_tableView.tableHeaderView = searchBarContainer;
}
Unfortunately the UISearchBar glitches in some scenarios that I couldn't isolate yet. I opted to calculate the contentSize manually by adding the height of all cells.

Starting from iOS11, UITableView uses estimate row/header/footer height to calculate initial contentSize by default. In fact, if you tap on the search bar and dismiss the keyboard, content size will have the correct value.
To fix this behavior, set estimate row, header and footer height to 0 in IB instead of Automatic:
or just do it programmatically:
self.tableView.estimatedRowHeight = 0;
self.tableView.estimatedSectionHeaderHeight = 0;
self.tableView.estimatedSectionFooterHeight = 0;

Add this delegate method
-(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
return [[UIView alloc] initWithFrame:CGRectZero];
}
Maybe your view for footer is groing up because there is no cells to show.

Related

iOS: UITableView won't load cells when left anchor is view.safeAreaLayoutGuide.leftAnchor, but will load if it is just view.leftAnchor

I have a view controller animating in from the left edge of screen, and this view controller has a UITableView subview.
On every device and orientation except for one (iPhone X in landscape), this table view shows properly.
On the iPhone X in landscape, the table view is in the correct place but its cells do not populate until you scroll the tableView. Once you scroll, the table view is as if it had been there the whole time but with invisible cells.
This constraint causes the cells to not load:
[tableView.leftAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.leftAnchor].active = YES;
And when replacing this constraint with the following, the problem is solved as well:
[tableView.leftAnchor constraintEqualToAnchor:self.view.leftAnchor].active = YES;
I've made the background of the UITableView red to show that it is correctly placed, but no rows are showing even though they load in the portrait orientation.
I've also tried leaving it as:
[tableView.leftAnchor constraintEqualToAnchor:self.view.leftAnchor].active = YES;
but doing:
[tableView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever];
which solves the problem for header cells:
but not content cells:
This code causes the same issue:
[tableView setInsetsContentViewsToSafeArea:YES];
I am setting up my regular cells like this :
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if([reuseIdentifier isEqual: #"LayerCell"]) {
_titleLabel = [[UILabel alloc] init];
_imgView = [[UIImageView alloc] init];
_toggleView = [[UIImageView alloc] init];
[_imgView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:_imgView];
[_imgView.heightAnchor constraintEqualToAnchor:self.heightAnchor multiplier:0.8].active = YES;
[_imgView.widthAnchor constraintEqualToAnchor:self.heightAnchor multiplier:0.8].active = YES;
[_imgView.centerYAnchor constraintEqualToAnchor:self.centerYAnchor].active = YES;
[_imgView.leftAnchor constraintEqualToAnchor:self.leftAnchor constant:8].active = YES;
[_imgView setContentMode:UIViewContentModeScaleAspectFit];
[self addSubview:_toggleView];
[_toggleView setTranslatesAutoresizingMaskIntoConstraints:NO];
[_toggleView.heightAnchor constraintEqualToAnchor:_imgView.heightAnchor].active = YES;
[_toggleView.widthAnchor constraintEqualToAnchor:_imgView.widthAnchor].active = YES;
[_toggleView.centerYAnchor constraintEqualToAnchor:_imgView.centerYAnchor].active = YES;
[_toggleView.rightAnchor constraintEqualToAnchor:self.rightAnchor constant:-10].active = YES;
[_toggleView setContentMode:UIViewContentModeScaleAspectFit];
[self addSubview:_titleLabel];
[_titleLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[_titleLabel.heightAnchor constraintEqualToConstant:20].active = YES;
[_titleLabel.centerYAnchor constraintEqualToAnchor:_imgView.centerYAnchor].active = YES;
[_titleLabel.rightAnchor constraintEqualToAnchor:_toggleView.leftAnchor constant:-10].active = YES;
[_titleLabel.leftAnchor constraintEqualToAnchor:_imgView.rightAnchor constant:10].active = YES;
[self layoutIfNeeded];
}
return self;
}

can't show headerVIew in tableVIew correctly

I create 2 custom tableViews when I use this code:
UITableView *mainTableView=[[MainTableView alloc]init];
[self.view addSubview:mainTableView];
The headerView I create didn't show.
UITableView *mainTableView=[[MainTableView alloc]init];
self.view=mainTableView;
This code shows the right view. What happened to my headerView?
UPDATE:MainTableView.m
+(instancetype)createMainView
{
return [[self alloc]init];
}
-(instancetype)initWithFrame:(CGRect)frame
{
self=[super initWithFrame:frame];
[self addmainTableView];
[self addHeadImageViewAndPageControl];
[self addTitleLabelAndNavigationButton];
return self;
}
#pragma mark -add view to main view
-(void)addHeadImageViewAndPageControl
{
UIScrollView *headImageView=[[UIScrollView alloc]init];
headImageView.frame=CGRectMake(0, 0, yScreenWidth, yScreenHeight/3);
headImageView.backgroundColor=[UIColor redColor];
self.tableHeaderView=headImageView;
//add pagecontroll
UIPageControl *headPageControl=[[UIPageControl alloc]initWithFrame:CGRectMake(-100, yScreenHeight/3-30, yScreenWidth/3, 25)];
headPageControl.numberOfPages=5;
headPageControl.pageIndicatorTintColor=[UIColor lightGrayColor];
headPageControl.currentPageIndicatorTintColor=[UIColor whiteColor];
headPageControl.currentPage=1;
[self.tableHeaderView addSubview:headPageControl];
}
this is my headerView.
The problem of your code is not set frame for Tableview. Put the code below before you add tableView to self.view.
self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
or
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

How to place a UIView above UITableView's section headers?

I tried to place a view on top of my table view. It seems to only cover the cells, but not the section headers. I want it to cover both cells and section headers.
In my UITableViewController subclass:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
UIView* veilView = [[UIView alloc] initWithFrame:CGRectMake(25.0f, 100.0f, 100.0f, 150.0f)];
veilView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.5f];
[self.view addSubview:veilView];
}
The section headers are constructed in a typical way:
- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
CustomTableSectionHeaderView* header = [[CustomTableSectionHeaderView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, tableView.frame.size.width, [CustomTableSectionHeaderView height])];
header.text = [self.displayAlphabet objectAtIndex:section];
return header;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return [CustomTableSectionHeaderView height];
}
Try changing the zPosition of the view after you create it.
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
UIView* veilView = [[UIView alloc] initWithFrame:CGRectMake(25.0f, 100.0f, 100.0f, 150.0f)];
veilView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.5f];
[self.view addSubview:veilView];
[self.addressTextView.layer setZPosition:1000]
}
Higher numbers are on top of other views, and the scale is arbitrary, so you can go as high as you like. The default value is 0, but section headers will have a higher value than that as they float over the cells they refer to when you're scrolling.
It was caused by a timing issue. I'm actually loading the data for the table from my server. I placed the overlay view before the server returned the data. When the server did return the data, I reload the table view, causing the section headers to be created on top of the overlay view.
This will solve the issue:
// When server returns table data:
[self.tableView reloadTable];
[self.veilView.superview bringSubviewToFront:self.veilView];

strage uitableview cell behavior: view moves inside cell

I am having some strange uitableview behavior- my customs cells have a little extra space around them that I cannot fix. I can also move the cells in that space. I have attached a couple of pictures as my English is not letting me to explain better. Any ideas on what might the issue be? I can post my code for my custom cell but it even happens with admob add cell, so I am not sure it is related to the custom cell.
EDIT: Added code for heights
EDIT2: I changed the scroll view alloc to
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width,self.bounds.size.height)];
And it fixed the moving of the cell. But that white line is still there.
Table View
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// return (self.tableViewHome.bounds.size.height-49-6-self.tableViewHome.tableHeaderView.bounds.size.height-self.tableViewHome.tableFooterView.bounds.size.height-GAD_SIZE_320x50.height)/3;
float height = self.tableViewHome.frame.size.height-self.tableViewHome.tableHeaderView.bounds.size.height-30.0;
if (indexPath.item==5)
{
height=kGADAdSizeBanner.size.height;
}
else
{
if (indexPath.item==1 || indexPath.item==3)
{
height=15.0;
}
else
{
if (indexPath.item==0 || indexPath.item==2 || indexPath.item==4)
{
height=(height-kGADAdSizeBanner.size.height)/3;
}
}
}
NSLog(#"Height:%f",height);
return height;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 0.1;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return 0.1;
}
Custom Cell
-(id) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self)
{
scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
scrollView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[scrollView setShowsHorizontalScrollIndicator:NO];
[scrollView setShowsVerticalScrollIndicator:NO];
// NSInteger viewcount= 3;
// for(int i = 0; i< viewcount; i++) {
// CGFloat x = 2 * self.bounds.size.width;
todayView = [HomeTodayView homeTodayView];
todayView.frame = CGRectMake(0, 0,self.bounds.size.width, self.bounds.size.height);
todayView.backgroundColor = [UIColor redColor];
avgView = [HomeAvgView homeAvgView];
avgView.frame = CGRectMake(self.bounds.size.width, 0, self.bounds.size.width, self.bounds.size.height);
// [[HomeTodayView alloc] initWithFrame:
todayView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
avgView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[scrollView addSubview:todayView];
[scrollView addSubview:avgView];
scrollView.contentSize = CGSizeMake(self.bounds.size.width *2, self.bounds.size.height+100);
scrollView.pagingEnabled = YES;
scrollView.bounces = NO;
[self addSubview:scrollView];
}
return self;
}
Try This:
[table setSeparatorStyle:UITableViewCellSeparatorStyleNone];
NOTE:- table = your tableview name.
If this does not work then please check that your custom cell height and the row height of tableView are same?

UITableView subclass with default style grouped

I have no clue how can I set grouped style as default to UITableView subclass. My goal is to get grouped TableView (ofc) but by something like that.
TableSubclass *myView = (TableSubclass*)some.other.view
Is this possible? I will be greatful for any advice.
UPDATE
I have ios 6 app with custom UITabBar and custom more section.
My "custom" code
- (void)viewDidLoad
{
[super viewDidLoad];
firstUse=true;
UINavigationController *moreController = self.moreNavigationController;
moreController.navigationBar.barStyle = UIBarStyleBlackOpaque;
self.moreNavigationController.delegate = self;
if ([moreController.topViewController.view isKindOfClass:[UITableView class]])
{
UITableView *view = (UITableView *)moreController.topViewController.view;
view = [view initWithFrame:view.frame style:UITableViewStyleGrouped];
UIView* bview = [[UIView alloc] init];
bview.backgroundColor = [UIColor blackColor];
[view setBackgroundView:bview];
moreTableViewDataSource = [[NXMoreTableViewDataSource alloc] initWithDataSource:view.dataSource];
view.dataSource = moreTableViewDataSource;
}
}
It's working great under 6 but under 7 UITableView don't respond but when I remove
[view initWithFrame:view.frame style:UITableViewStyleGrouped];
It respond again but I lose grouped style.
Are you sure that the table view is not yet configured?
from UITableView Class Reference
When you create a UITableView instance you must specify a table style,
and this style cannot be changed
Have a look how to create and configure UITableView.
Generally you use UITableViewController and then in:
- (void)loadView
{
UITableView *tableView =
[[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]
style:UITableViewStylePlain];
...
}

Resources