This question already has answers here:
Eliminate extra separators below UITableView
(34 answers)
Closed 6 years ago.
i am trying to display a simple UITableView with some data. I wish to set the static height of the UITableView so that it doesn't displays empty cells at the end of the table. how do I do that?
code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"%d", [arr count]);
return [arr count];
}
Set a zero height table footer view (perhaps in your viewDidLoad method), like so:
Swift:
tableView.tableFooterView = UIView()
Objective-C:
tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
Because the table thinks there is a footer to show, it doesn't display any cells beyond those you explicitly asked for.
Interface builder pro-tip:
If you are using a xib/Storyboard, you can just drag a UIView (with height 0pt) onto the bottom of the UITableView.
Swift 3 syntax:
tableView.tableFooterView = UIView(frame: .zero)
Swift syntax: < 2.0
tableView.tableFooterView = UIView(frame: CGRect.zeroRect)
Swift 2.0 syntax:
tableView.tableFooterView = UIView(frame: CGRect.zero)
In the Storyboard, select the UITableView, and modify the property Style from Plain to Grouped.
Implemented with swift on Xcode 6.1
self.tableView.tableFooterView = UIView(frame: CGRectZero)
self.tableView.tableFooterView?.hidden = true
The second line of code does not cause any effect on presentation, you can use to check if is hidden or not.
Answer taken from this link
Fail to hide empty cells in UITableView Swift
I can not add comment as of now so adding this as an answer.
#Andy's answer is good and the same results can be achieved with the following line of code:
tableView.tableFooterView = [UIView new];
'new' method belongs to NSObject class and invokes alloc and init methods for UIView.
I tried the code:
tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
In the viewDidLoad section and xcode6 showed a warning. I have put a "self." in front of it and now it works fine. so the working code I use is:
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
or you can call tableView method to set the footer height in 1 point, and it will add an last line, but you can hide it too, by setting footer background color.
code:
func tableView(tableView: UITableView,heightForFooterInSection section: Int) -> CGFloat {
return 1
}
looks like last line
override func viewWillAppear(animated: Bool) {
self.tableView.tableFooterView = UIView(frame: CGRect.zeroRect)
/// OR
self.tableView.tableFooterView = UIView()
}
Using UITableViewController
The solution accepted will change the height of the TableViewCell. To fix that, perform following steps:
Write code snippet given below in ViewDidLoad method.
tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
Add following method in the TableViewClass.m file.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return (cell height set on storyboard);
}
That's it. You can build and run your project.
in the below method:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (([array count]*65) > [UIScreen mainScreen].bounds.size.height - 66)
{
Table.frame = CGRectMake(0, 66, self.view.frame.size.width, [array count]*65));
}
else
{
Table.frame = CGRectMake(0, 66, self.view.frame.size.width, [UIScreen mainScreen].bounds.size.height - 66);
}
return [array count];
}
here 65 is the height of the cell and 66 is the height of the navigation bar in UIViewController.
Related
I have a xib file with a UITableView for which I want to add a custom section header view using the delegate method tableView:viewForHeaderInSection:. Is there any possibility to design it in Interface Builder and then change some of it's subview's properties programmatically?
My UITableView has more section headers so creating one UIView in Interface Builder and returning it doesn't work, because I'd have to duplicate it, but there isn't any good method of doing it. Archiving and unarchiving it doesn't work for UIImages so UIImageViews would show up blank.
Also, I don't want to create them programmatically because they are too complex and the resulting code would be hard to read and maintain.
Edit 1: Here is my tableView:viewForHeaderInSection: method:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
if ([tableView.dataSource tableView:tableView numberOfRowsInSection:section] == 0) {
return nil;
}
CGSize headerSize = CGSizeMake(self.view.frame.size.width, 100);
/* wrapper */
UIView *wrapperView = [UIView viewWithSize:headerSize];
wrapperView.backgroundColor = [UIColor colorWithHexString:#"2670ce"];
/* title */
CGPoint titleMargin = CGPointMake(15, 8);
UILabel *titleLabel = [UILabel labelWithText:self.categoriesNames[section] andFrame:CGEasyRectMake(titleMargin, CGSizeMake(headerSize.width - titleMargin.x * 2, 20))];
titleLabel.textColor = [UIColor whiteColor];
titleLabel.font = [UIFont fontWithStyle:FontStyleRegular andSize:14];
[wrapperView addSubview:titleLabel];
/* body wrapper */
CGPoint bodyWrapperMargin = CGPointMake(10, 8);
CGPoint bodyWrapperViewOrigin = CGPointMake(bodyWrapperMargin.x, CGRectGetMaxY(titleLabel.frame) + bodyWrapperMargin.y);
CGSize bodyWrapperViewSize = CGSizeMake(headerSize.width - bodyWrapperMargin.x * 2, headerSize.height - bodyWrapperViewOrigin.y - bodyWrapperMargin.y);
UIView *bodyWrapperView = [UIView viewWithFrame:CGEasyRectMake(bodyWrapperViewOrigin, bodyWrapperViewSize)];
[wrapperView addSubview:bodyWrapperView];
/* image */
NSInteger imageSize = 56;
NSString *imageName = [self getCategoryResourceItem:section + 1][#"image"];
UIImageView *imageView = [UIImageView imageViewWithImage:[UIImage imageNamed:imageName] andFrame:CGEasyRectMake(CGPointZero, CGEqualSizeMake(imageSize))];
imageView.layer.masksToBounds = YES;
imageView.layer.cornerRadius = imageSize / 2;
[bodyWrapperView addSubview:imageView];
/* labels */
NSInteger labelsWidth = 60;
UILabel *firstLabel = [UILabel labelWithText:#"first" andFrame:CGRectMake(imageSize + bodyWrapperMargin.x, 0, labelsWidth, 16)];
[bodyWrapperView addSubview:firstLabel];
UILabel *secondLabel = [UILabel labelWithText:#"second" andFrame:CGRectMake(imageSize + bodyWrapperMargin.x, 20, labelsWidth, 16)];
[bodyWrapperView addSubview:secondLabel];
UILabel *thirdLabel = [UILabel labelWithText:#"third" andFrame:CGRectMake(imageSize + bodyWrapperMargin.x, 40, labelsWidth, 16)];
[bodyWrapperView addSubview:thirdLabel];
[#[ firstLabel, secondLabel, thirdLabel ] forEachView:^(UIView *view) {
UILabel *label = (UILabel *)view;
label.textColor = [UIColor whiteColor];
label.font = [UIFont fontWithStyle:FontStyleLight andSize:11];
}];
/* line */
UIView *lineView = [UIView viewWithFrame:CGRectMake(imageSize + labelsWidth + bodyWrapperMargin.x * 2, bodyWrapperMargin.y, 1, bodyWrapperView.frame.size.height - bodyWrapperMargin.y * 2)];
lineView.backgroundColor = [UIColor whiteColorWithAlpha:0.2];
[bodyWrapperView addSubview:lineView];
/* progress */
CGPoint progressSliderOrigin = CGPointMake(imageSize + labelsWidth + bodyWrapperMargin.x * 3 + 1, bodyWrapperView.frame.size.height / 2 - 15);
CGSize progressSliderSize = CGSizeMake(bodyWrapperViewSize.width - bodyWrapperMargin.x - progressSliderOrigin.x, 30);
UISlider *progressSlider = [UISlider viewWithFrame:CGEasyRectMake(progressSliderOrigin, progressSliderSize)];
progressSlider.value = [self getCategoryProgress];
[bodyWrapperView addSubview:progressSlider];
return wrapperView;
}
and I would want it to look something like this:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
if ([tableView.dataSource tableView:tableView numberOfRowsInSection:section] == 0) {
return nil;
}
SectionView *sectionView = ... // get the view that is already designed in the Interface Builder
sectionView.headerText = self.categoriesNames[section];
sectionView.headerImage = [self getCategoryResourceItem:section + 1][#"image"];
sectionView.firstLabelText = #"first";
sectionView.secondLabelText = #"second";
sectionView.thirdLabelText = #"third";
sectionView.progress = [self getCategoryProgress];
return wrapperView;
}
Edit 2: I'm not using a Storyboard, just .xib files. Also, I don't have an UITableViewController, just an UIViewController in which I added an UITableView.
#Storyboard or XIB. Updated for 2020.
Same Storyboard:
return tableView.dequeueReusableCell(withIdentifier: "header")
Separate XIB (Additional step: you must register that Nib first):
tableView.register(UINib(nibName: "XIBSectionHeader", bundle:nil),
forCellReuseIdentifier: "xibheader")
To load from a Storyboard instead of a XIB, see this Stack Overflow answer.
#Using UITableViewCell to create Section Header in IB
Take advantage of the fact that a section header is a regular UIView, and that UITableViewCell is, too, a UIView. In Interface Builder, drag & drop a Table View Cell from the Object Library onto your Table View Prototype Content.
(2020) In modern Xcode, simply increase the "Dynamic Prototypes" number to drop in more cells:
Add an Identifier to the newly added Table View Cell, and customize its appearance to suit your needs. For this example, I used header.
Use dequeueReusableCell:withIdentifier to locate the cell, just like you would any table view cell.
Don't forget it is just a normal cell: but you are going to use it as a header.
For 2020, simply add to ViewDidLoad the four lines of code:
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 70 // any reasonable value is fine
tableView.sectionHeaderHeight = UITableView.automaticDimension
tableView.estimatedSectionHeaderHeight = 70 // any reasonable value is fine
{See for example this for a discussion.}
Your header cell heights are now completely dynamic. It's fine to change the length of the texts, etc, in the headers.
(TiP: Purely regarding the storyboard: simply select...
...in storyboard, so that the storyboard will work correctly. This has absolutely no effect on the final build. Selecting that checkbox has absolutely no effect whatsoever on the final build. It purely exists to make the storyboard work correctly, if the height is dynamic.)
In older Xcode, or, if for some reason you do not wish to use dynamic heights:
simply supply heightForHeaderInSection, which is hardcoded as 44 for clarity in this example:
//MARK: UITableViewDelegate
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
// This is where you would change section header content
return tableView.dequeueReusableCell(withIdentifier: "header")
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
{
return 44
}
###Swift 2 & earlier:
return tableView.dequeueReusableCellWithIdentifier("header") as? UIView
self.tableView.registerNib(UINib(nibName: "XIBSectionHeader", bundle:nil),
forCellReuseIdentifier: "xibheader")
► Find this solution on GitHub and additional details on Swift Recipes.
I finally solved it using this tutorial, which, largely consists of the following (adapted to my example):
Create SectionHeaderView class that subclasses UIView.
Create SectionHeaderView.xib file and set it's File's Owner's CustomClass to the SectionHeaderView class.
Create an UIView property in the .m file like: #property (strong, nonatomic) IBOutlet UIView *viewContent;
Connect the .xib's View to this viewContent outlet.
Add an initializer method that looks like this:
+ (instancetype)header {
SectionHeaderView *sectionHeaderView = [[SectionHeaderView alloc] init];
if (sectionHeaderView) { // important part
sectionHeaderView.viewContent = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:sectionHeaderView options:nil] firstObject];
[sectionHeaderView addSubview:sectionHeaderView.viewContent];
return sectionHeaderView;
}
return nil;
}
Then, I added an UILabel inside the .xib file and connected it to the labelCategoryName outlet and implemented the setCategoryName: method inside the SectionHeaderView class like this:
- (void)setCategoryName:(NSString *)categoryName {
self.labelCategoryName.text = categoryName;
}
I then implemented the tableView:viewForHeaderInSection: method like this:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
SectionHeaderView *sectionHeaderView = [SectionHeaderView header];
[sectionHeaderView setCategoryName:self.categoriesNames[section]];
return sectionHeaderView;
}
And it finally worked. Every section has it's own name, and also UIImageViews show up properly.
Hope it helps others that stumble over the same wrong solutions over and over again, all over the web, like I did.
Solution Is way simple
Create one xib, make UI according to your Documentation
then in viewForHeaderInSection get xib
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
NSArray *nibArray = [[NSBundle mainBundle] loadNibNamed:#"HeaderView" owner:self options:nil];
HeaderView *headerView = [nibArray objectAtIndex:0];
return headerView;
}
As far as I understand your problem, you want to have the same UIView duplicated multiple times for the multiple section headers you want to be able to display.
If this were my problem, here is how I would solve it.
ORIGINAL SOLUTION
1)
In my UIViewController that owns the table view, I'd also create a view that's a template for the header. Assign that to a IBOutlet. This will be the view you can edit via Interface Builder.
2)
In your ViewDidLoad or (maybe better) ViewWillAppear method, you'll want to make as many copies of that header template UIView as you'll need to display for section headers.
Making copies of UIViews in memory isn't trivial, but it isn't hard either. Here is an answer from a related question that shows you how to do it.
Add the copies to a NSMutableArray (where the index of each object will correspond to the sections... the view in index 0 of the array will be what you return for section 0, view 1 in the array for section 1, ec.).
3)
You will not be able to use IBOutlets for the elements of that section header (because your code only associates outlets with one particular view from the XIB file).
So for this, you'll probably want to use view tag properties for each of the UI elements in your header view that you'll want to modify/change for each different section. You can set these tags via Interface Builder and then refer to them programmatically in your code.
In your viewForHeaderInSection method, you'll do something like:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
if ([tableView.dataSource tableView:tableView numberOfRowsInSection:section] == 0) {
return nil;
}
SectionView *sectionView = [self.arrayOfDuplicatedHeaderViews objectAtIndex: section];
// my title view has a tag of 10
UILabel *titleToModify = [sectionView viewWithTag: 10];
if(titleToModify)
{
titleToModify.text = [NSString stringWithFormat:#"section %d", section];
}
return sectionView;
}
Makes sense?
DIFFERENT SOLUTION
1)
You'd still need an array of UIViews (or "Section View" subclassed UIViews) but you could create each of those with successive calls to load the view from it's own XIB file.
Something like this:
#implementation SectionView
+ (SectionView*) getSectionView
{
NSArray* array = [[NSBundle mainBundle] loadNibNamed:#"SectionView" owner:nil options:nil];
return [array objectAtIndex:0]; // assume that SectionView is the only object in the xib
}
#end
(more detail found in the answer to this related question)
2)
You might be able to use IBOutlets on this (but I'm not 100% certain), but tag properties once again might work pretty well.
I was trying to mimic a view like the iOS 7 "Shortcut".
I used a UITableViewController with static cells, 1 section and 2 rows. For the text "Create a shortcut that ...", I tried UILabel as well as the section footer. The problem with footer was that I could not figure out a way to wrap the long text to multiple lines. So I am curious about what's the "standard" or preferred way to implement the text under sections? Thanks!
If you select the Table View Section in the storyboard and enter your text in the 'Footer' it will automatically wrap.
If you want more control over the font you can set a custom footer view using -[UITableViewDelegate tableView:viewForFooterInSection:]
The following code replicates what you've shown above. Instead of creating a label and returning it, I created a simple UIView that was some arbitrary hard-coded height (you may want to change that to suit your needs), and then created a label and added the label to the view, returning the view, so that you could center the label in the view as I did when I created the frame. By setting the number of lines to 0 you are effectively telling the label there will be multiple lines, and I set an autoresizing mask on the label so that if the view rotates the text will still remain centered in the view with 10 points padding on either side. You'll also want to make sure you are returning the appropriate heightForFooterInSection in case you decide to add something below it later it won't be overlapping your footer.
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 80)];
UILabel *explanationLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, self.view.frame.size.width - 20, 80)];
explanationLabel.textColor = [UIColor darkGrayColor];
explanationLabel.numberOfLines = 0;
explanationLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
explanationLabel.text = #"Create a shortcut that will automatically expand into the word or phrase as you type.";
[footerView addSubview:explanationLabel];
return footerView;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return 80;
}
Gave me this:
SWIFT 4 Version
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 80))
let explanationLabel = UILabel(frame: CGRect(x: 10, y: 0, width: view.frame.size.width - 20, height: 80))
explanationLabel.textColor = UIColor.darkGray
explanationLabel.numberOfLines = 0
explanationLabel.text = tableDataSectionFooters[section]
footerView.addSubview(explanationLabel as? UIView ?? UIView())
return footerView
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 80
}
Use UILabel in the footer and set it to wrap lines (number of lines = 0)
all other answers are right in using the UILabel, but to achieve the 100% identical effect you must use the attributedText property of the label. Than you can also add the indention showed in the original shortcut screenshot.
This question already has answers here:
Eliminate extra separators below UITableView
(34 answers)
Closed 6 years ago.
i am trying to display a simple UITableView with some data. I wish to set the static height of the UITableView so that it doesn't displays empty cells at the end of the table. how do I do that?
code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"%d", [arr count]);
return [arr count];
}
Set a zero height table footer view (perhaps in your viewDidLoad method), like so:
Swift:
tableView.tableFooterView = UIView()
Objective-C:
tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
Because the table thinks there is a footer to show, it doesn't display any cells beyond those you explicitly asked for.
Interface builder pro-tip:
If you are using a xib/Storyboard, you can just drag a UIView (with height 0pt) onto the bottom of the UITableView.
Swift 3 syntax:
tableView.tableFooterView = UIView(frame: .zero)
Swift syntax: < 2.0
tableView.tableFooterView = UIView(frame: CGRect.zeroRect)
Swift 2.0 syntax:
tableView.tableFooterView = UIView(frame: CGRect.zero)
In the Storyboard, select the UITableView, and modify the property Style from Plain to Grouped.
Implemented with swift on Xcode 6.1
self.tableView.tableFooterView = UIView(frame: CGRectZero)
self.tableView.tableFooterView?.hidden = true
The second line of code does not cause any effect on presentation, you can use to check if is hidden or not.
Answer taken from this link
Fail to hide empty cells in UITableView Swift
I can not add comment as of now so adding this as an answer.
#Andy's answer is good and the same results can be achieved with the following line of code:
tableView.tableFooterView = [UIView new];
'new' method belongs to NSObject class and invokes alloc and init methods for UIView.
I tried the code:
tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
In the viewDidLoad section and xcode6 showed a warning. I have put a "self." in front of it and now it works fine. so the working code I use is:
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
or you can call tableView method to set the footer height in 1 point, and it will add an last line, but you can hide it too, by setting footer background color.
code:
func tableView(tableView: UITableView,heightForFooterInSection section: Int) -> CGFloat {
return 1
}
looks like last line
override func viewWillAppear(animated: Bool) {
self.tableView.tableFooterView = UIView(frame: CGRect.zeroRect)
/// OR
self.tableView.tableFooterView = UIView()
}
Using UITableViewController
The solution accepted will change the height of the TableViewCell. To fix that, perform following steps:
Write code snippet given below in ViewDidLoad method.
tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
Add following method in the TableViewClass.m file.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return (cell height set on storyboard);
}
That's it. You can build and run your project.
in the below method:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (([array count]*65) > [UIScreen mainScreen].bounds.size.height - 66)
{
Table.frame = CGRectMake(0, 66, self.view.frame.size.width, [array count]*65));
}
else
{
Table.frame = CGRectMake(0, 66, self.view.frame.size.width, [UIScreen mainScreen].bounds.size.height - 66);
}
return [array count];
}
here 65 is the height of the cell and 66 is the height of the navigation bar in UIViewController.
The question is what's the right-most way to display a separator in the last cell in a table/section.
Basically this is what I am after.
This is from the native music app, which makes me think that it should be possible to achieve just by means of UITableView, they would not be using some private API for cell separators, right?
I know you can get away without using actual separators, but adding one pixel line in the bottom of the cell. But I'm not a fan of this approach because
When a cell is selected/highlighted its separator and the separator of the previous cell are automatically hidden (see the second screenshot with "You've got to be crazy" selected). And this is
something I want UITableView to handle instead of doing myself if I use one-pixel line
(which is especially handy when cell separators do not extend all
the way to the edge of the table view, separators and selected cell background do not look nice together).
I would like to keep my cells as flat as possible for scrolling performance.
Also there is something in UITableView reference that makes me think that there is an easy way to get what I want:
In iOS 7 and later, cell separators do not extend all the way to the
edge of the table view. This property sets the default inset for all
cells in the table, much like rowHeight sets the default height for
cells. It is also used for managing the “extra” separators drawn at
the bottom of plain style tables.
Does somebody know how exactly to use these “extra” separators drawn at the bottom of plain style tables? Because this is exactly what I need.
I thought assigning separatorInsetto the UITableView, not UITableViewCell would do the trick, but it does not, the last cell is still missing its separator.
Right now I only see one option: to have a custom section footer to mimic the separator for the last cell. And this is not good, especially if you want to have an actual section footer using tableView:titleForFooterInSection: method.
This worked flawlessly for me to add a separator to the last cell. have fun!
self.tableView.tableFooterView = [[UIView alloc] init];
When you add headerView or footerView to your TableView, last separator line will disappear.
Example below will let you make workaround for showing separator on the last cell. The only thing you have to implement more is to make this separator disappearing after selecting cell, so behavior is the same like in the rest of cells.
For Swift 4.0
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let result = UIView()
// recreate insets from existing ones in the table view
let insets = tableView.separatorInset
let width = tableView.bounds.width - insets.left - insets.right
let sepFrame = CGRect(x: insets.left, y: -0.5, width: width, height: 0.5)
// create layer with separator, setting color
let sep = CALayer()
sep.frame = sepFrame
sep.backgroundColor = tableView.separatorColor?.cgColor
result.layer.addSublayer(sep)
return result
}
I just found something that works for me. In a few words: give your UITableView a tableFooterView and set its frame's height to 0. This makes an actual separator show, with the right insets.
In more details: if you are using the storyboard, drag a UIView to the bottom of your Table View (in the tree view on the left) so it shows just below Table View Cell, at the same hierarchical level. This creates a tableFooterView. Of course this can be done programmatically as well.
Then, in your UITableViewController's implementation:
UIView *footerView = self.tableView.tableFooterView;
CGRect footerFrame = footerView.frame;
footerFrame.size.height = 0;
[footerView setFrame:footerFrame];
Let me know if that works for you! It might also work for the first separator if you use a tableHeaderView instead, I haven't tried it though.
So here's a super simple solution in Swift 4 which works:
Inside override func viewDidLoad(){}, I simply implemented this line of code:
self.tableView.tableFooterView = UIView(frame: .zero)
Hence it ensures that only the last cell gets the separator inset.
This worked perfectly for me, hope it does for you too!
this will do exactly what you want .. even though the line will take the entire width of the cell:
in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
self.tableView.separatorColor = [UIColor redColor];
self.tableView.separatorInset = UIEdgeInsetsZero;
You can do something like this if you are not using sections:
- (void)viewDidLoad
{
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(insetLeftSide, 0, width - insetRightSide, 1)];
}
If you are using sections implement the footer in each section as a one point View in the methods
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
}
This will allow you to have a separator for your last cell which in fact is not a separator is a footer that you can play with it and make it look like a separator
Swift 3
I found this old issue, so I tried the same in Swift:
tableView.tableFooterView = UIView()
tableView.tableFooterView?.height = 0 // Maybe not necessary
But it lead to another problem (in my case). So I solved it differently. I added an extra cell at the end of this section, empty and with height equal to zero:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return previousNumberOfRows + 1
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return indexPath.row == previousNumberOfRows ? 0 : previousCellHeight
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == items.count {
return UITableViewCell()
} else {
previousCellInitialization()
}
This is a less concise solution, but works in more cases, if you have multiple sections, existing footer view(s)...
I had a similar issue and found a workaround. Apple hides the last uitableviewcell separator and then displays it if you select the cell or if you call select and deselect on that cell.
So I taught the best is in - (void)layoutSubviews. The separator view is called _separatorView and it's a private property. Using the cell's selected / highlighted states you can come up with something like this:
- (void)layoutSubviews
{
// Call super so the OS can do it's layout first
[super layoutSubviews];
// Get the separator view
UIView *separatorView = [self valueForKey:#"_separatorView"];
// Make the custom inset
CGRect newFrame = CGRectMake(0.0, 0.0, self.bounds.size.width, separatorView.frame.size.height);
newFrame = CGRectInset(newFrame, 15.0, 0.0);
[separatorView setFrame:newFrame];
// Show or hide the bar based on cell state
if (!self.selected) {
separatorView.hidden = NO;
}
if (self.isHighlighted) {
separatorView.hidden = YES;
}
}
Something like this.
In iOS 8, if you have a plain style UITableView, and add a footer, the last separator is gone. However, you can easily recreate it by adding a custom separator view to the footer.
This example exactly mimics Today Widget separator style
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
//create footer view
let result = UIView()
result.frame.size.height = tableView.rowHeight
//recreate last cell separator, which gets hidden by footer
let sepFrame = CGRectMake(15, -0.5, tableView.frame.width, 0.5);
let vibrancyEffectView = UIVisualEffectView.init(effect: UIVibrancyEffect.notificationCenterVibrancyEffect())
vibrancyEffectView.frame = sepFrame
vibrancyEffectView.contentView.backgroundColor = tableView.separatorColor
result.addSubview(vibrancyEffectView)
return result
}
If you add an empty footer then the tableview will remove all the remaining line separators (for non-existent cells) but will still include the separator for the last cell:
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
return [UIView new];
}
I used the table view style "grouped" to add this line:
And furthermore it avoids sticking the last separator line to stick on the screen when scrolling out!
Works in iOS 7.x and 8.x (put it in cellForRowAtIndexPath):
(PS substitute "max elements of your datasource" with your array datasource count)
if (row == <max elements of your datasource>-1) {
UIView* separatorLineView = [[UIView alloc] initWithFrame:CGRectMake(0, cell.contentView.frame.size.height-1, self.view.frame.size.width, 1)];/// change size as you need.
separatorLineView.tag = 666;
separatorLineView.backgroundColor = [UIColor colorWithRed: 204.0/255.0 green: 204.0/255.0 blue: 204.0/255.0 alpha:1.0];
UIView *separator = [cell.contentView viewWithTag:666];
// case of orientation changed..
if (separator.frame.size.width != cell.contentView.frame.size.width) {
[[cell.contentView viewWithTag:666] removeFromSuperview];
separator = nil;
}
if (separator==nil) [cell.contentView addSubview:separatorLineView];
}
This is definitely help. Working.
but set separator "none" from attribute inspector.
Write following code in cellForRowAtIndexPath method
if(indexPath.row==arrData.count-1){
UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0,
cell.contentView.frame.size.height - 1.0,
cell.contentView.frame.size.width, 1)];
lineView.backgroundColor = [UIColor blackColor];
[cell.contentView addSubview:lineView];
}
The code below worked for me:
UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 0.35)];
footerView.backgroundColor = [UIColor whiteColor];
CGRect frame = footerView.frame;
frame.origin.x = 15;
frame.size.width = frame.size.width - 15;
UIView *blackView = [[UIView alloc] initWithFrame:frame];
[blackView setBackgroundColor:[UIColor blackColor]];
blackView.alpha = 0.25;
[footerView addSubview:blackView];
tableView.tableFooterView = footerView;
Hope it works for you too.
When I set up a table view with 4 rows, there are still extra separators lines (or extra blank cells) below the filled rows.
How would I remove these cells?
Interface builder (iOS 9+)
Just drag a UIView to the table. In storyboard, it will sit at the top below your custom cells. You may prefer to name it "footer".
Here it is shown in green for clarity, you'd probably want clear color.
Note that by adjusting the height, you can affect how the "bottom bounce" of the table is handled, as you prefer. (Height zero is usually fine).
To do it programmatically:
Swift
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.tableFooterView = UIView()
}
Objective-C
iOS 6.1+
- (void)viewDidLoad
{
[super viewDidLoad];
// This will remove extra separators from tableview
self.tableView.tableFooterView = [UIView new];
}
or if you prefer,
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
Historically in iOS:
Add to the table view controller...
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
// This will create a "invisible" footer
return CGFLOAT_MIN;
}
and if necessary...
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
return [UIView new];
// If you are not using ARC:
// return [[UIView new] autorelease];
}
Here's another way to do that w/out the grouped table style, and one you'd probably not guess. Adding a header and footer to the table (perhaps one or the other suffices, haven't checked) causes the separators to disappear from the filler/blank rows.
I stumbled onto this because I wanted a little space at the top and bottom of tables to decrease the risk of hitting buttons instead of a table cell with meaty fingers. Here's a method to stick a blank view in as header and footer. Use whatever height you like, you still eliminate the extra separator lines.
- (void) addHeaderAndFooter
{
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 10)];
v.backgroundColor = [UIColor clearColor];
[self.myTableView setTableHeaderView:v];
[self.myTableView setTableFooterView:v];
[v release];
}
In response to #Casebash, I went back to the code in my app ("AcmeLists" List Manager in iTunes store...) and short-circuited the addHeaderAndFooter method to verify. Without it, I have the extra row separators; with the code, I have what you see in this window snap: no table row separators picture. So I'm not sure why it wouldn't have worked for you. Moreover, it makes sense to me that having any custom footer on a table view would necessarily have to stop drawing row separators for blank rows below it. That would be hideous. For reference, I looked at tables where there were more rows than could be viewed on screen, and then for a table with two rows. In both cases, no extraneous separators.
Perhaps your custom views were not actually added. To check that, set the background color to something other than clearColor, e.g., [UIColor redColor]. If you don't see some red bars at the bottom of the table, your footer wasn't set.
Removing extra separator lines for empty rows in UITableView in Swift
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.yourTableview.tableFooterView = UIView()
}
I would like to extend wkw answer:
Simply adding only footer with height 0 will do the trick. (tested on sdk 4.2, 4.4.1)
- (void) addFooter
{
UIView *v = [[UIView alloc] initWithFrame:CGRectZero];
[self.myTableView setTableFooterView:v];
}
or even simpler - where you set up your tableview, add this line:
//change height value if extra space is needed at the bottom.
[_tableView setTableFooterView:[[UIView alloc] initWithFrame:CGRectMake(0,0,0,0)]];
or even simplier - to simply remove any separators:
[_tableView setTableFooterView:[UIView new]];
Thanks to wkw again :)
For iOS 7+ using Storyboards
Simply drag a UIView into your UITableView as the footer. Set the footer view's height to 0.
Try this. It worked for me:
- (void) viewDidLoad
{
[super viewDidLoad];
// Without ARC
//self.tableView.tableFooterView = [[[UIView alloc] init] autorelease];
// With ARC, tried on Xcode 5
self.tableView.tableFooterView = [UIView new];
}
If you are using Swift, add the following code to viewDidLoad of the controller that manages the tableview:
override func viewDidLoad() {
super.viewDidLoad()
//...
// Remove extra separators
tableView.tableFooterView = UIView()
}
For Swift:
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableFooterView = UIView()
}
You can just add an empty footer at the end then it will hide the empty cells but it will also look quite ugly:
tableView.tableFooterView = UIView()
There is a better approach: add a 1 point line at the end of the table view as the footer and the empty cells will also not been shown anymore.
let footerView = UIView()
footerView.frame = CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 1)
footerView.backgroundColor = tableView.separatorColor
tableView.tableFooterView = footerView
just add this code (Swift) . .
tableView.tableFooterView = UIView()
Advancing J. Costa's solution: You can make a global change to the table by putting this line of code:
[[UITableView appearance] setTableFooterView:[[UIView alloc] initWithFrame:CGRectZero]];
inside the first possible method (usually in AppDelegate, in: application:didFinishLaunchingWithOptions: method).
Swift works great with:
tableView.tableFooterView = UIView()
I know this Question has be accepted answer but i put here different ways for how to hide Extra separator line of UITableView.
You can hide tableView's standard separator line, and add your custom line at the top of each cell.
Update:
The easiest way to add custom separator is to add simple UIView of 1px height:
UIView* separatorLineView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 1)];
separatorLineView.backgroundColor = [UIColor grayColor]; /// may be here is clearColor;
[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
The best and simple way i like ever is
self.tableView.tableFooterView = [[UIView alloc] init];
Try any of one;
You may find lots of answers to this question. Most of them around manipulation with UITableView's tableFooterView attribute and this is proper way to hide empty rows. For the conveniency I've created simple extension which allows to turn on/off empty rows from Interface Builder.
You can check it out from this gist file. I hope it could save a little of your time.
extension UITableView {
#IBInspectable
var isEmptyRowsHidden: Bool {
get {
return tableFooterView != nil
}
set {
if newValue {
tableFooterView = UIView(frame: .zero)
} else {
tableFooterView = nil
}
}
}
}
Usage:
tableView.isEmptyRowsHidden = true
uitableview extra separator line hide extra separators lines hide in swift 3.0
self.tbltableView.tableFooterView = UIView(frame: .zero)
If you don't want any separator after the last cell, then you need a close to zero but non-zero height for your footer.
In your UITableViewDelegate:
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return .leastNormalMagnitude
}
Just add an view with the desired separator color as background color, 100% width, 1px height at the position x0 y-1 to your tableViewCell. Make sure the tableViewCell doesn't clip subviews, instead the tableView should.
So you get a absolut simple and working separator only between existing cells without any hack per code or IB.
Note: On a vertical top bounce the 1st separator shows up, but that shouldn't be a problem cause it's the default iOS behavior.
I was using a table view to show a fixed number of fixed height rows, so I simply resized it and made it non-scrollable.
To eliminate extra separator lines from bottom of UItableview programmatically, just write down following two lines of code and it will remove extra separator from it.
tableView.sectionFooterHeight = 0.f;
tableView.sectionHeaderHeight = 0.f;
This trick working for me all the time, try yourself.
I had some luck implementing a single piece of the accepted answer (iOS 9+, Swift 2.2). I had tried implementing:
self.tableView.tableFooterView = UIView(frame: .zero)
However, there was no effect on my tableView - I believe it may have something to do with the fact that I was using UITableViewController.
Instead, I only had to override the viewForFooterInSection method (I did not set the tableFooterView elsewhere):
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
return UIView(frame: .zero)
}
This worked fine for a tableView with a single section (if you have multiple sections, you need to specify the last one).
If you have only one section, then the quickest and easiest way is to just set the Table View Style from "Plain" to "Grouped". (see image)
If you have more sections, you might need to set the header height to zero (depending on your/your customer's/your project manager's taste)
If you have more sections, and don't want to mess with the headers (even if it is just one line in the simplest case), then you need to set a UIView as a footer, as it was explained in the previous answers)
Swift 4.0 Extension
Just a little extension for the storyboard:
extension UITableView {
#IBInspectable
var hideSeparatorForEmptyCells: Bool {
set {
tableFooterView = newValue ? UIView() : nil
}
get {
return tableFooterView == nil
}
}
}
Quick and easy Swift 4 way.
override func viewDidLoad() {
tableView.tableFooterView = UIView(frame: .zero)
}
If you are having static cells. You can also turn off the separator from Inspector window. (this won't be desirable if you need the separator. In that case use method shown above)
Try with this
for Objective C
- (void)viewDidLoad
{
[super viewDidLoad];
// This will remove extra separators from tableview
self.yourTableView.tableFooterView = [UIView new];
}
for Swift
override func viewDidLoad() {
super.viewDidLoad()
self.yourTableView.tableFooterView = UIView()
}
If you want to remove unwanted space in UITableview you can use below two methods
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return 0.1;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return 0.1;
}
I have added this small tableview extension that helps throughout
extension UITableView {
func removeExtraCells() {
tableFooterView = UIView(frame: .zero)
}
}
Swift 3 /Swift 4 /Swift 5 +, Very Easy and simple way
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//MARK:- For Hiding the extra lines in table view.
tableView?.tableFooterView = UIView()
}
OR
override func viewDidLoad(_ animated: Bool) {
super.viewDidLoad(animated)
//MARK:- For Hiding the extra lines in table view.
tableView?.tableFooterView = UIView()
}
Try this
self.tables.tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 10.0f)];
UIKit does not create empty cell when the tableView has a tableFooterView. So we can make a trick and assign a zero height UIView object as footer of the tableView.
tableView.tableFooterView = UIView()
In case you have a searchbar in your view (to limit the number of results for example), you have to also add the following in shouldReloadTableForSearchString and shouldReloadTableForSearchScope:
controller.searchResultsTable.footerView = [ [ UIView alloc ] initWithFrame:CGRectZero ];