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

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];

Related

UITableView header doesn't listen to scroll

I have a simple UITable and i want a little image before the table starts, so i use a tableheader so far so good, this works quite nicely
self.table.tableHeaderView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:img]];
only the weird thing is when i try to scroll on a table view row the table scrolls but when i try to scroll on the header nothing happens, its like the scroll listener isnt listening to to the scroll event on the header.
Just to be clear the header does scroll when you scroll the table as one piece ( and that is the desired behaviour )
Im googleling like crazy but kant seem to find the answer, thanks!!
some extra code
- (void)viewDidLoad
{
[super viewDidLoad];
// set the table header
self.table.tableHeaderView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"header"]];
// add empty footer view to hide empty cells
self.table.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
// set title
self.navigationItem.title = [self.catData objectForKey:#"titlePage"] ? [self.catData objectForKey:#"titlePage"] : [self.catData objectForKey:#"title"];
}
Use Grouped Tableview. then you can scroll your table view.
Have you tried setting your header view with :
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
return [[UIImageView alloc] initWithImage:[UIImage imageNamed:img]];
}
You need to implement this below method:--
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGRect rect = self.tableView.tableHeaderView.frame;
rect.origin.y = MIN(0, self.tableView.contentOffset.y);
self.tableView.tableHeaderView.frame = rect;
}

Hiding UITableView footer

I am unable to hide my UITableView footer (i.e. setting it's height to 0 and animating the transition).
I tried to wrap tableView.tableViewFooter.height = 0 (and tableView.tableViewFooter = nil) between [tableView beginUpdates] and [tableView endUpdates] but it doesn't work.
Implementing the method below creates another footer.
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return 50;
}
Is there a difference between a tableview footer and a section footer? I created mine by dropping a button under my tableview in my storyboard.
Any ideas to do this simply?
Ok here's how I solved this problem.
- (void)refreshTableFooterButton
{
if (should be visible) {
self.tableView.tableFooterView = self.tableFooterButton;
} else {
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
}
}
I used [[UIView alloc] initWithFrame:CGRectZero instead of nil to prevent unwanted empty cells to appear in the tableview.
I didn't need an animation block, but other people might.
[UIView animateWithDuration:0.5 animations:^{
}];
Also, i had to keep a strong reference to my tableFooterButton IBOutlet. That was part of why my initial attempt at solving the problem failed. I'm not sure if having a strong reference to an IBOutlet is good practice though. Feel free to leave a comment about that.
using the following code :
self.tableView.tableFooterView?.hidden = false
This should do the trick. There are other alternatives such as this answer here.
tableView.sectionHeaderHeight = 0.0;
tableView.sectionFooterHeight = 0.0;
-(CGFloat)tableView:(UITableView*)tableView heightForHeaderInSection:(NSInteger)section
{
return 1.0;
-(CGFloat)tableView:(UITableView*)tableView heightForFooterInSection:(NSInteger)section
{
return 1.0;
}
-(UIView*)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section
{
return [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
}
-(UIView*)tableView:(UITableView*)tableView viewForFooterInSection:(NSInteger)section
{
return [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
}`
use following methods :
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 0.0f;
}
-(UIView*)tableView:(UITableView*)tableView viewForFooterInSection:(NSInteger)section
{
return [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
}`
So in the end here's the simplest solution I can give you. So as you can see I just put the .m (for simplicity).
There is a difference between table footer and section footer. What you're looking for is the section footer.
I also added an animation block for adding and removing it.
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
UIButton *_footerButton;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self createAndAddFooterButton];
}
-(void) buttonPressed:(id)button
{
[UIView animateWithDuration:2 animations:^{
self.tableView.tableFooterView = nil;
}];
}
- (void)createAndAddFooterButton
{
// here you create the button
_footerButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[_footerButton setTitle:#"Button Title" forState:UIControlStateNormal];
[_footerButton sizeToFit];
[_footerButton addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[UIView animateWithDuration:2 animations:^{
self.tableView.tableFooterView = _footerButton;
}];
}
#end
My problem was that the clear line was the footer which I could only define as 1 pixel high and not 0 (as I do not want to have a footer).
The only way I could fix it was to provide a view in viewForFooterInSection and set the background colour to the same as the header, so that visually you don't notice, and when I animate-in new rows they do not show through the top of the header where the clear line (footer) was.
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let blankView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 1))
blankView.backgroundColor = {Same colour as Header}
return blankView

UITableView contentSize wrong when using UISearchBar

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.

Hide remove separator line if UITableViewCells are empty [duplicate]

This question already has answers here:
Eliminate extra separators below UITableView
(34 answers)
Closed 6 years ago.
I have a UITableView and I have only 3 rows in it, and I can see those 3 rows. The problem is the cells that are empty: I can see lines there. I don't want to see those lines.
Any idea how to remove those lines?
Below is image for what I am looking for.
Even simpler than Andrey Z's reply:
Simply make a bogus tableFooterView in your UITableView class:
self.tableFooterView = [UIView new]; // to hide empty cells
and Swift:
tableFooterView = UIView()
You can hide UITableView's standard separator line by using any one of the below snippets of code.
The easiest way to add a custom separator is to add a simple UIView of 1px height:
UIView* separatorLineView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 1)];
separatorLineView.backgroundColor = [UIColor clearColor]; // set color as you want.
[cell.contentView addSubview:separatorLineView];
OR
self.tblView=[[UITableView alloc] initWithFrame:CGRectMake(0,0,320,370) style:UITableViewStylePlain];
self.tblView.delegate=self;
self.tblView.dataSource=self;
[self.view addSubview:self.tblView];
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 10)];
v.backgroundColor = [UIColor clearColor];
[self.tblView setTableHeaderView:v];
[self.tblView setTableFooterView:v];
[v release];
OR
- (float)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
// This will create a "invisible" footer
return 0.01f;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
// To "clear" the footer view
return [[UIView new] autorelease];
}
OR
And also check nickfalk's answer, it is very short and helpful too.
And you should also try this single line,
self.tableView.tableFooterView = [[UIView alloc] init];
Not sure but it's working in all the version of iOS that I checked, with iOS 5 and later, up to iOS 7.
Updated answer for swift & iOS 9. This works for tableviews of the .Plain variety.
tableView.tableFooterView = UIView()
Transparent UIView as a tableView footer with 1px height will do the trick.
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 1)];
v.backgroundColor = [UIColor clearColor];
[self.tableView setTableFooterView:v];
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
Use this Code for remove separator line for empty cells.
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
// This will create a "invisible" footer
return 0.01f;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
return [UIView new];
// If you are not using ARC:
// return [[UIView new] autorelease];
}
Just returning an empty UIView() in viewForFooterInSection worked for me:
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
return UIView()
}
Please try the following code:
self.tblView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
if ([self.tblView respondsToSelector:#selector(setSeparatorInset:)])
{
[self.tblView setSeparatorInset:UIEdgeInsetsZero];
}
// write in view did load
tableForBrands.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
None of suggested answers were suitable for my similar problem. Implementing this method in tableView delegate finally worked:
- (void)tableView:(UITableView *)tableView
willDisplayCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath
{
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
}
If you are using Storyboards you can just drag and drop an UIView into your UITableView below your cells and set its height to 0. (Have only tested in an iOS 8 project)
I guess this is what you are looking for.
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
return 1.0f;
}
You can set the table view to be grouped instead of plain - this changes the look a bit but at least removes the extra lines.
I had this exact problem and ended up changing to grouped views. Looks a lot better.
Some of previous suggestions contain a BIG conceptual error:
if You do:
[cell addSubview: ....
even time a cell is "reused", you will add a new subview for the divider!
avoid it in two ways:
a) use a TAG, and:
1) ask for a subview for that tag
let divider = cell.viewWithTag(TAG) ...
2) if present, do NOT add another subview
3) if NOT present add AND tag it.
b) create a custom view and ADD your custom divider in "init" "awakeFromNib" of custom cell.
code for a):
if let divider = cell.viewWithTag(DIVIDER_TAG) as? UIView{
// nothing.. eventually change color bases in IndexPath...
}else{
let frame = CGRectMake(0, cell.frame.height-1, cell.frame.width, 1)
divider.tag = DIVIDER_TAG
divider.backgroundColor = UIColor.redColor()
cell.addSubview(divider)
}
Swift Solution:
tableView.tableFooterView = UIView(frame: CGRectZero)
Worked on Xcode 7.2
Inside the cellForRowAtIndexPath
let separatorLineView:UIView = UIView(frame: CGRectMake(0,0,self.tableview.bounds.width,0.5))
separatorLineView.backgroundColor = tableView.separatorColor
cell!.contentView.addSubview(separatorLineView)

How to change custom viewForHeaderInSection width after rotation

I have to build a custom tableViewHeader in which at least two labels should be displayed, viz. a projectName and projectDescription. The contents of these two labels vary (i.e. in terms of string-length).
I managed to get a working version for the default device orientation (portrait) but if the user rotates the device to landscape the width of my custom headerView is not adjusted, and the user will see unused white space to the right.
The following code fragment is being used:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 50.0f;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
CGFloat wd = tableView.bounds.size.width;
CGFloat ht = tableView.bounds.size.height;
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0., 0., wd, ht)];
headerView.contentMode = UIViewContentModeScaleToFill;
// Add project name/description as labels to the headerView.
UILabel *projName = [[UILabel alloc] initWithFrame:CGRectMake(5., 5., wd, 20)];
UILabel *projDesc = [[UILabel alloc] initWithFrame:CGRectMake(5., 25., wd, 20)];
projName.text = #"Project: this project is about an interesting ..";
projDesc.text = #"Description: a very long description should be more readable when your device is in landscape mode!";
[headerView addSubview:projName];
[headerView addSubview:projDesc];
return headerView;
}
I noticed that the tableView:viewForHeaderInSection: will only be called once after viewDidLoad, but not after a device orientation change.
Should I implement the willRotateToInterfaceOrientation: method with something like:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration
{
[self.tableView reloadSections:nil withRowAnimation:UITableViewRowAnimationNone];
}
I cannot figure out how to get the reloadSections: to work, forcing a recalculation of my customView.
If you use autoresizingMask the header adjusts correctly on rotation. No need to override anything else. I would set the automasks at the end of the code just before returning the view:
[headerView addSubview:projName];
[headerView addSubview:projDesc];
projName.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
projDesc.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
headerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
return headerView;

Resources