I'm customizing a UITableView. I want to hide the line separating on the last cell ... can i do this?
I know I can do tableView.separatorStyle = UITableViewCellStyle.None but that would affect all the cells of the tableView. I want it to only affect my last cell.
in viewDidLoad, add this line:
self.tableView.separatorColor = [UIColor clearColor];
and in cellForRowAtIndexPath:
for iOS lower versions
if(indexPath.row != self.newCarArray.count-1){
UIImageView *line = [[UIImageView alloc] initWithFrame:CGRectMake(0, 44, 320, 2)];
line.backgroundColor = [UIColor redColor];
[cell addSubview:line];
}
for iOS 7 upper versions (including iOS 8)
if (indexPath.row == self.newCarArray.count-1) {
cell.separatorInset = UIEdgeInsetsMake(0.f, cell.bounds.size.width, 0.f, 0.f);
}
In the UITableViewDataSource cellForRowAtIndexPath method
Swift :
if indexPath.row == {your row number} {
cell.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: .greatestFiniteMagnitude)
}
or :
cell.separatorInset = UIEdgeInsetsMake(0, 0, 0, UIScreen.main.bounds.width)
for default Margin:
cell.separatorInset = UIEdgeInsetsMake(0, tCell.layoutMargins.left, 0, 0)
to show separator end-to-end
cell.separatorInset = .zero
Objective-C:
if (indexPath.row == {your row number}) {
cell.separatorInset = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, CGFLOAT_MAX);
}
To follow up on Hiren's answer.
in ViewDidLoad and the following line :
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
Or, if you are using XIB's or Storyboards change "separator" to "none" :
And in CellForRowAtIndexPath add this :
CGFloat separatorInset; // Separator x position
CGFloat separatorHeight;
CGFloat separatorWidth;
CGFloat separatorY;
UIImageView *separator;
UIColor *separatorBGColor;
separatorY = cell.frame.size.height;
separatorHeight = (1.0 / [UIScreen mainScreen].scale); // This assures you to have a 1px line height whatever the screen resolution
separatorWidth = cell.frame.size.width;
separatorInset = 15.0f;
separatorBGColor = [UIColor colorWithRed: 204.0/255.0 green: 204.0/255.0 blue: 204.0/255.0 alpha:1.0];
separator = [[UIImageView alloc] initWithFrame:CGRectMake(separatorInset, separatorY, separatorWidth,separatorHeight)];
separator.backgroundColor = separatorBGColor;
[cell addSubView: separator];
Here is an example of the result where I display a tableview with dynamic Cells (but only have a single one with contents). The result being that only that one has a separator and not all the "dummy" ones tableview automatically adds to fill the screen.
EDIT: For those who don't always read the comments, there actually is a better way to do it with a few lines of code :
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableFooterView = UIView()
}
If you don't want to draw the separator yourself, use this:
// Hide the cell separator by moving it to the far right
cell.separatorInset = UIEdgeInsetsMake(0, 10000, 0, 0);
This API is only available starting from iOS 7 though.
Set separatorInset.right = .greatestFiniteMagnitude on your cell.
my develop environment is
Xcode 7.0
7A220 Swift 2.0
iOS 9.0
above answers not fully work for me
after try, my finally working solution is:
let indent_large_enought_to_hidden:CGFloat = 10000
cell.separatorInset = UIEdgeInsetsMake(0, indent_large_enought_to_hidden, 0, 0) // indent large engough for separator(including cell' content) to hidden separator
cell.indentationWidth = indent_large_enought_to_hidden * -1 // adjust the cell's content to show normally
cell.indentationLevel = 1 // must add this, otherwise default is 0, now actual indentation = indentationWidth * indentationLevel = 10000 * 1 = -10000
and the effect is:
In Swift 3, Swift 4 and Swift 5, you can write an extension to UITableViewCell like this:
extension UITableViewCell {
func separator(hide: Bool) {
separatorInset.left = hide ? bounds.size.width : 0
}
}
Then you can use this as below (when cell is your cell instance):
cell.separator(hide: false) // Shows separator
cell.separator(hide: true) // Hides separator
It is really better assigning the width of table view cell as left inset instead of assigning it some random number. Because in some screen dimensions, maybe not now but in future your separators can still be visible because that random number may not be enough. Also, in iPad in landscape mode you can't guarantee that your separators will always be invisible.
In your UITableViewCell subclass, override layoutSubviews and hide the _UITableViewCellSeparatorView. Works under iOS 10.
override func layoutSubviews() {
super.layoutSubviews()
subviews.forEach { (view) in
if view.dynamicType.description() == "_UITableViewCellSeparatorView" {
view.hidden = true
}
}
}
Better solution for iOS 7 & 8
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
DLog(#"");
if (cell && indexPath.row == 0 && indexPath.section == 0) {
DLog(#"cell.bounds.size.width %f", cell.bounds.size.width);
cell.separatorInset = UIEdgeInsetsMake(0.f, cell.bounds.size.width, 0.f, 0.0f);
}
}
If your app is rotatable — use 3000.0f for left inset constant or calc it on the fly.
If you try to set right inset you have visible part of separator on the left side of cell on iOS 8.
In iOS 7, the UITableView grouped style cell separator looks a bit different. It looks a bit like this:
I tried Kemenaran's answer of doing this:
cell.separatorInset = UIEdgeInsetsMake(0, 10000, 0, 0);
However that doesn't seem to work for me. I'm not sure why. So I decided to use Hiren's answer, but using UIView instead of UIImageView, and draws the line in the iOS 7 style:
UIColor iOS7LineColor = [UIColor colorWithRed:0.82f green:0.82f blue:0.82f alpha:1.0f];
//First cell in a section
if (indexPath.row == 0) {
UIView *line = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 1)];
line.backgroundColor = iOS7LineColor;
[cell addSubview:line];
[cell bringSubviewToFront:line];
} else if (indexPath.row == [self.tableViewCellSubtitles count] - 1) {
UIView *line = [[UIView alloc] initWithFrame:CGRectMake(21, 0, self.view.frame.size.width, 1)];
line.backgroundColor = iOS7LineColor;
[cell addSubview:line];
[cell bringSubviewToFront:line];
UIView *lineBottom = [[UIView alloc] initWithFrame:CGRectMake(0, 43, self.view.frame.size.width, 1)];
lineBottom.backgroundColor = iOS7LineColor;
[cell addSubview:lineBottom];
[cell bringSubviewToFront:lineBottom];
} else {
//Last cell in the table view
UIView *line = [[UIView alloc] initWithFrame:CGRectMake(21, 0, self.view.frame.size.width, 1)];
line.backgroundColor = iOS7LineColor;
[cell addSubview:line];
[cell bringSubviewToFront:line];
}
If you use this, make sure you plug in the correct table view height in the second if statement. I hope this is useful for someone.
In Swift using iOS 8.4:
/*
Tells the delegate that the table view is about to draw a cell for a particular row. (optional)
*/
override func tableView(tableView: UITableView,
willDisplayCell cell: UITableViewCell,
forRowAtIndexPath indexPath: NSIndexPath)
{
if indexPath.row == 3 {
// Hiding separator line for only one specific UITableViewCell
cell.separatorInset = UIEdgeInsetsMake(0, cell.bounds.size.width, 0, 0)
}
}
Note: this snippet above will work on UITableView using dynamic cells. The only problem that you can encounter is when you use static cells with categories, a separator type different than none and a grouped style for the table view. In fact, in this particular case it will not hide the last cell of each category. For overcoming that, the solution that I found was to set the cell separator (through IB) to none and then creating and adding manually (through code) your line view to each cell. For an example, please check the snippet below:
/*
Tells the delegate that the table view is about to draw a cell for a particular row. (optional)
*/
override func tableView(tableView: UITableView,
willDisplayCell cell: UITableViewCell,
forRowAtIndexPath indexPath: NSIndexPath)
{
// Row 2 at Section 2
if indexPath.row == 1 && indexPath.section == 1 {
// Hiding separator line for one specific UITableViewCell
cell.separatorInset = UIEdgeInsetsMake(0, cell.bounds.size.width, 0, 0)
// Here we add a line at the bottom of the cell (e.g. here at the second row of the second section).
let additionalSeparatorThickness = CGFloat(1)
let additionalSeparator = UIView(frame: CGRectMake(0,
cell.frame.size.height - additionalSeparatorThickness,
cell.frame.size.width,
additionalSeparatorThickness))
additionalSeparator.backgroundColor = UIColor.redColor()
cell.addSubview(additionalSeparator)
}
}
I do not believe this approach will work under any circumstance with dynamic cells...
if (indexPath.row == self.newCarArray.count-1) {
cell.separatorInset = UIEdgeInsetsMake(0.f, cell.bounds.size.width, 0.f, 0.f);
}
It doesn't matter which tableview method you do it in for dynamic cells the cell you changed the inset property on will always have the inset property set now every time it is dequeued causing a rampage of missing line separators... That is until you change it yourself.
Something like this worked for me:
if indexPath.row == franchises.count - 1 {
cell.separatorInset = UIEdgeInsetsMake(0, cell.contentView.bounds.width, 0, 0)
} else {
cell.separatorInset = UIEdgeInsetsMake(0, 0, cell.contentView.bounds.width, 0)
}
That way you update ur data structure state at every load
In willdisplaycell:
cell.separatorInset = UIEdgeInsetsMake(0, cell.bounds.size.width, 0, 0)
The much more simple and logical is to do this:
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
return [[UIView alloc] initWithFrame:CGRectZero];
}
In most cases you don't want to see only the last table view cell separator. And this approach removes only the last table view cell separator, and you don't need to think about Auto Layout issues (i.e. rotating device) or hardcode values to set up separator insets.
Use this subclass, set separatorInset does not work for iOS 9.2.1, content would be squeezed.
#interface NSPZeroMarginCell : UITableViewCell
#property (nonatomic, assign) BOOL separatorHidden;
#end
#implementation NSPZeroMarginCell
- (void) layoutSubviews {
[super layoutSubviews];
for (UIView *view in self.subviews) {
if (![view isKindOfClass:[UIControl class]]) {
if (CGRectGetHeight(view.frame) < 3) {
view.hidden = self.separatorHidden;
}
}
}
}
#end
https://gist.github.com/liruqi/9a5add4669e8d9cd3ee9
Using Swift 3 and adopting the fastest hacking-method, you can improve code using extensions:
extension UITableViewCell {
var isSeparatorHidden: Bool {
get {
return self.separatorInset.right != 0
}
set {
if newValue {
self.separatorInset = UIEdgeInsetsMake(0, self.bounds.size.width, 0, 0)
} else {
self.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0)
}
}
}
}
Then, when you configure cell:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "identifier", for: indexPath)
switch indexPath.row {
case 3:
cell.isSeparatorHidden = true
default:
cell.isSeparatorHidden = false
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
if cell.isSeparatorHidden {
// do stuff
}
}
if([_data count] == 0 ){
[self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];// [self tableView].=YES;
} else {
[self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine];//// [self tableView].hidden=NO;
}
The best way to achieve this is to turn off default line separators, subclass UITableViewCell and add a custom line separator as a subview of the contentView - see below a custom cell that is used to present an object of type SNStock that has two string properties, ticker and name:
import UIKit
private let kSNStockCellCellHeight: CGFloat = 65.0
private let kSNStockCellCellLineSeparatorHorizontalPaddingRatio: CGFloat = 0.03
private let kSNStockCellCellLineSeparatorBackgroundColorAlpha: CGFloat = 0.3
private let kSNStockCellCellLineSeparatorHeight: CGFloat = 1
class SNStockCell: UITableViewCell {
private let primaryTextColor: UIColor
private let secondaryTextColor: UIColor
private let customLineSeparatorView: UIView
var showsCustomLineSeparator: Bool {
get {
return !customLineSeparatorView.hidden
}
set(showsCustomLineSeparator) {
customLineSeparatorView.hidden = !showsCustomLineSeparator
}
}
var customLineSeparatorColor: UIColor? {
get {
return customLineSeparatorView.backgroundColor
}
set(customLineSeparatorColor) {
customLineSeparatorView.backgroundColor = customLineSeparatorColor?.colorWithAlphaComponent(kSNStockCellCellLineSeparatorBackgroundColorAlpha)
}
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
init(reuseIdentifier: String, primaryTextColor: UIColor, secondaryTextColor: UIColor) {
self.primaryTextColor = primaryTextColor
self.secondaryTextColor = secondaryTextColor
self.customLineSeparatorView = UIView(frame:CGRectZero)
super.init(style: UITableViewCellStyle.Subtitle, reuseIdentifier:reuseIdentifier)
selectionStyle = UITableViewCellSelectionStyle.None
backgroundColor = UIColor.clearColor()
contentView.addSubview(customLineSeparatorView)
customLineSeparatorView.hidden = true
}
override func prepareForReuse() {
super.prepareForReuse()
self.showsCustomLineSeparator = false
}
// MARK: Layout
override func layoutSubviews() {
super.layoutSubviews()
layoutCustomLineSeparator()
}
private func layoutCustomLineSeparator() {
let horizontalPadding: CGFloat = bounds.width * kSNStockCellCellLineSeparatorHorizontalPaddingRatio
let lineSeparatorWidth: CGFloat = bounds.width - horizontalPadding * 2;
customLineSeparatorView.frame = CGRectMake(horizontalPadding,
kSNStockCellCellHeight - kSNStockCellCellLineSeparatorHeight,
lineSeparatorWidth,
kSNStockCellCellLineSeparatorHeight)
}
// MARK: Public Class API
class func cellHeight() -> CGFloat {
return kSNStockCellCellHeight
}
// MARK: Public API
func configureWithStock(stock: SNStock) {
textLabel!.text = stock.ticker as String
textLabel!.textColor = primaryTextColor
detailTextLabel!.text = stock.name as String
detailTextLabel!.textColor = secondaryTextColor
setNeedsLayout()
}
}
To disable the default line separator use, tableView.separatorStyle = UITableViewCellSeparatorStyle.None;. The consumer side is relatively simple, see example below:
private func stockCell(tableView: UITableView, indexPath:NSIndexPath) -> UITableViewCell {
var cell : SNStockCell? = tableView.dequeueReusableCellWithIdentifier(stockCellReuseIdentifier) as? SNStockCell
if (cell == nil) {
cell = SNStockCell(reuseIdentifier:stockCellReuseIdentifier, primaryTextColor:primaryTextColor, secondaryTextColor:secondaryTextColor)
}
cell!.configureWithStock(stockAtIndexPath(indexPath))
cell!.showsCustomLineSeparator = true
cell!.customLineSeparatorColor = tintColor
return cell!
}
For Swift 2:
add the following line to viewDidLoad():
tableView.separatorColor = UIColor.clearColor()
cell.separatorInset = UIEdgeInsetsMake(0.0, cell.bounds.size.width, 0.0, -cell.bounds.size.width)
works well in iOS 10.2
Swift 5 - iOS13+
When you are defininig your table, just add:
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
// Removes separator lines
tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
return UIView()
}
The magic line is tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
Try the below code, might help you resolve your problem
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString* reuseIdentifier = #"Contact Cell";
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if (nil == cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
if (indexPath.row != 10) {//Specify the cell number
cell.backgroundView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"bgWithLine.png"]];
} else {
cell.backgroundView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"bgWithOutLine.png"]];
}
}
return cell;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *cellId = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
NSInteger lastRowIndexInSection = [tableView numberOfRowsInSection:indexPath.section] - 1;
if (row == lastRowIndexInSection) {
CGFloat halfWidthOfCell = cell.frame.size.width / 2;
cell.separatorInset = UIEdgeInsetsMake(0, halfWidthOfCell, 0, halfWidthOfCell);
}
}
You have to take custom cell and add Label and set constraint such as label should cover entire cell area.
and write the below line in constructor.
- (void)awakeFromNib {
// Initialization code
self.separatorInset = UIEdgeInsetsMake(0, 10000, 0, 0);
//self.layoutMargins = UIEdgeInsetsZero;
[self setBackgroundColor:[UIColor clearColor]];
[self setSelectionStyle:UITableViewCellSelectionStyleNone];
}
Also set UITableView Layout margin as follow
tblSignup.layoutMargins = UIEdgeInsetsZero;
I couldn't hide the separator on a specific cell except using the following workaround
- (void)layoutSubviews {
[super layoutSubviews];
[self hideCellSeparator];
}
// workaround
- (void)hideCellSeparator {
for (UIView *view in self.subviews) {
if (![view isKindOfClass:[UIControl class]]) {
[view removeFromSuperview];
}
}
}
For iOS7 and above, the cleaner way is to use INFINITY instead of hardcoded value. You don't have to worry on updating the cell when the screen rotates.
if (indexPath.row == <row number>) {
cell.separatorInset = UIEdgeInsetsMake(0, INFINITY, 0, 0);
}
As (many) others have pointed out, you can easily hide all UITableViewCell separators by simply turning them off for the entire UITableView itself; eg in your UITableViewController
- (void)viewDidLoad {
...
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
...
}
Unfortunately, its a real PITA to do on a per-cell basis, which is what you are really asking.
Personally, I've tried numerous permutations of changing the cell.separatorInset.left, again, as (many) others have suggested, but the problem is, to quote Apple (emphasis added):
"...You can use this property to add space between the current cell’s contents and the left and right edges of the table. Positive inset values move the cell content and cell separator inward and away from the table edges..."
So if you try to 'hide' the separator by shoving it offscreen to the right, you can end up also indenting your cell's contentView too. As suggested by crifan, you can then try to compensate for this nasty side-effect by setting cell.indentationWidth and cell.indentationLevel appropriately to move everything back, but I've found this to also be unreliable (content still getting indented...).
The most reliable way I've found is to over-ride layoutSubviews in a simple UITableViewCell subclass and set the right inset so that it hits the left inset, making the separator have 0 width and so invisible [this needs to be done in layoutSubviews to automatically handle rotations]. I also add a convenience method to my subclass to turn this on.
#interface MyTableViewCellSubclass()
#property BOOL separatorIsHidden;
#end
#implementation MyTableViewCellSubclass
- (void)hideSeparator
{
_separatorIsHidden = YES;
}
- (void)layoutSubviews
{
[super layoutSubviews];
if (_separatorIsHidden) {
UIEdgeInsets inset = self.separatorInset;
inset.right = self.bounds.size.width - inset.left;
self.separatorInset = inset;
}
}
#end
Caveat: there isn't a reliable way to restore the original right inset, so you cant 'un-hide' the separator, hence why I'm using an irreversible hideSeparator method (vs exposing separatorIsHidden). Please note the separatorInset persists across reused cells so, because you can't 'un-hide', you need to keep these hidden-separator cells isolated in their own reuseIdentifier.
if the accepted answer doesn't work, you can try this:
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return 0.01f; }
It's great ;)
My requirement was to hide the separator between 4th and 5th cell. I achieved it by
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if(indexPath.row == 3)
{
cell.separatorInset = UIEdgeInsetsMake(0, cell.bounds.size.width, 0, 0);
}
}
Inside the tableview cell class. put these line of code
separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: self.bounds.size.width)
Related
How do I remove the lines indicated in the picture? I have tried the following suggestions and none of them have worked for me,
How do I remove the borders of a UITableView?
Remove separator line for only one cell
Hide separator line on one UITableViewCell
This is my current code in cellForRowAt:
if (indexPath.row == place_sections[indexPath.section].rows.count - 1) {
cell.separatorInset.left = 1000
//cell.layer.borderWidth = 0
//cell.separatorInset = UIEdgeInsetsMake(0, 160, 0, 160);
}
if (indexPath.row == 0) {
cell.separatorInset.left = 1000
//cell.layer.borderWidth = 0
//cell.separatorInset = UIEdgeInsetsMake(0, 160, 0, 160);
// self.tableview.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: self.tableview.frame.width, height: 1))
}
Thank you
Separator between header and cell belongs to first cell in section.
When I used standard UITableViewHeaderFooterView and UITableViewCell I managed to hide line between header and cell via this code:
let contentView = cell.contentView
if
// this separator is subview of first UITableViewCell in section
indexPath.row == 0,
// truing to find it in subviews
let divider = cell.subviews.filter({ $0.frame.minY == 0 && $0 !== contentView }).first
{
divider.isHidden = true
}
This piece of code must be invoked in tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
This is objective c code, this help you
http://www.iostute.com/2015/04/expandable-and-collapsable-tableview.html
For both swift and objective c
http://www.anexinet.com/blog/expandable-collapsible-uitableview-sections/
The 1st link has custom header view, so border lines won't come here.
Comment this code in viewForHeaderInSection function
// /********** Add a custom Separator with Section view *******************/
// UIView* separatorLineView = [[UIView alloc] initWithFrame:CGRectMake(15, 40, _expandableTableView.frame.size.width-15, 1)];
// separatorLineView.backgroundColor = [UIColor blackColor];
// [sectionView addSubview:separatorLineView];
See the screen shot
The closest I could solve this problem is to change UITableView's Style from "Grouped" to "Plain".
I wouldn't recommend it if you can find a better solution because now the section headers stick to the top of the screen when scrolling, which is undesirable (I believe the proper way to describe this is "the section headers float").
I have a static TableView set up in my storyboard and i'm trying to remove the separator in the last cell for aesthetic purposes. I've looked at the various answers on this site and other websites and they all point to this type of code for IOS8
self.tableView.tableFooterView = UIView()
However when I run the app the separator is still there. Not too sure what i'm doing wrong.
Swift 5 Version of top voted answer:
tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 1))
It works even if the number of cells is dynamic.
One smart way to remove the separator from last cell is to add a plain view with height of 1 only.
tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 1)];
I'm using the code showing below for iOS 15+ since other solutions stop working.
This solution requires subclassing UITableViewCell, and manual top/bottom cell checks on cell creation time, so it's not that ideal. I would love to know a better solution.
class TableViewCell : UITableViewCell {
var hidesTopSeparator = false
var hidesBottomSeparator = false
override func layoutSubviews() {
super.layoutSubviews()
let topSeparator = subviews.first { $0.frame.minY == 0 && $0.frame.height <= 1 }
let bottomSeparator = subviews.first { $0.frame.minY >= bounds.maxY - 1 && $0.frame.height <= 1 }
topSeparator?.isHidden = hidesTopSeparator
bottomSeparator?.isHidden = hidesBottomSeparator
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let reuseID = "cell"
let cell = tableView.dequeueReusableCell(withIdentifier: reuseID) as? TableViewCell ?? .init(style: .default, reuseIdentifier: reuseID)
let numberOfRows = self.tableView(tableView, numberOfRowsInSection: indexPath.section)
cell.hidesTopSeparator = indexPath.row == 0
cell.hidesBottomSeparator = indexPath.row == numberOfRows - 1
return cell
}
I solved this problem by moving the Separator out of the view, so that I cannot see it
if indexPath.row == settings.count-1{
cell.separatorInset = UIEdgeInsets.init(
top: 0, left: 400,
bottom: 0, right: 0)
}else{
cell.separatorInset = .zero
}
This solution will remove the last separator in each section of grouped tables, without needing to subclass the table or the cells.
Works in iOS 8. (Probably works in iOS 6+).
Add the following to your delegate:
#pragma mark - UITableViewDelegate
- (CGFloat) tableView:(UITableView*)table
heightForFooterInSection:(NSInteger)section {
// Hide the separator when the table is first displayed
// of any sections that are visible on the screen.
[self hideBottomSeparator:table];
return 0.01f; // Or whatever you already return.
}
- (void) scrollViewDidScroll:(UITableView*)table {
// Hide separators that are visible after table scrolls.
// Check that event did not come from other scrollers
// in the table.
if ([table isKindOfClass:UITableView.class]) {
[self hideBottomSeparator:table];
}
}
- (void) hideBottomSeparator:(UITableView*)table {
for (UIView* cell in table.visibleCells) {
[self removeBottomSeparatorFromCell:cell];
}
}
- (void) removeBottomSeparatorFromCell:(UITableViewCell*)cell {
for (UIView* view in cell.subviews) {
if (view.frame.origin.x == 0 &&
view.frame.origin.y > cell.frame.size.height - 2 &&
view.frame.size.width == cell.frame.size.width &&
view.frame.size.height < 2) {
[view removeFromSuperview];
}
}
}
It works by removing any thin UIViews in the visible cells that are full width and at the bottom of the cell (it leaves the top separator visible).
To remove the top separator as well, comment out the origin.y check
If you want to remove the separator from a particular section(s) you would have to get the section numbers from the cells.
Note: because it removes separators by size (and position) alone, it could fail for non-default table (or cell) inset values, or if iOS changes the look of the separator. Also, it could fail if iOS is changed so that the separators are not subviews of the cells, in which case some more rigorous scanning would be required to find the separator views.
It relies on iOS adding the cells to the table before calling heightForFooterInSection:
Also, as above, it will remove all separators from a plain table.
The following solution should work, since all that is required is a simple calculation:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return self.tableView.frame.height/X+1/X
}
X is the number of cells you want in that table.
Swift 5
the frame has to be 1 pixel above. So set y coord to -1
tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: -1, width: tableView.frame.size.width, height: 1))
iOS 15
Since things changed since iOS 15 here is a simple and clean solution how to control a cell's separators.
The original separators are not accessible in a clean way, therefore I build custom ones that look the same, plus are easy to customize.
class CustomTableViewCell: UITableViewCell {
private let topSeparator = UIView(frame: .zero)
private let botSeparator = UIView(frame: .zero)
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupSeparators()
}
private func setupSeparators() {
// Removes original separators
separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: .greatestFiniteMagnitude)
topSeparator.backgroundColor = .lightGray
botSeparator.backgroundColor = .lightGray
contentView.addSubview(topSeparator)
contentView.addSubview(botSeparator)
topSeparator.translatesAutoresizingMaskIntoConstraints = false
botSeparator.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
topSeparator.topAnchor.constraint(equalTo: contentView.topAnchor),
topSeparator.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
topSeparator.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
topSeparator.heightAnchor.constraint(equalToConstant: 0.5),
botSeparator.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
botSeparator.trailingAnchor.constraint(equalTo: topSeparator.trailingAnchor),
botSeparator.leadingAnchor.constraint(equalTo: topSeparator.leadingAnchor),
botSeparator.heightAnchor.constraint(equalTo: topSeparator.heightAnchor)
])
}
func setup(hideTopSeparator: Bool, hideBotSeparator: Bool) {
topSeparator.isHidden = hideTopSeparator
botSeparator.isHidden = hideBotSeparator
}
//...
}
You can then set up the separators and your data through the controller like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CustomTableViewCell.cellIdentifier) as! CustomTableViewCell
cell.setup(hideTopSeparator: indexPath.row == 0,
hideBotSeparator: indexPath.row == datasource.count - 1)
return cell
}
As others pointed out, setting a footer view no longer removes the last separator on iOS 15+. By pushing the separator out of frame, we can achieve the same result. This is my general solution:
if indexPath == tableView.lastCellIndexPath {
// Push the separator line out of frame
cell.separatorInset = UIEdgeInsets(top: 0, left: tableView.bounds.width + 1, bottom: 0, right: 0)
} else {
cell.separatorInset = .zero
}
With UITableView extension:
extension UITableView {
/// Calculates the last cell index path if available
var lastCellIndexPath: IndexPath? {
for section in (0..<self.numberOfSections).reversed() {
let rows = numberOfRows(inSection: section)
guard rows > 0 else { continue }
return IndexPath(row: rows - 1, section: section)
}
return nil
}
}
Caveat
This solution won't work when you're not reloading the entire table view or cells are moved in the last index path. Also, it turns out if you're using Diffable Data Sources and try to reload the previous last items, this reload will happen in the cell provider before the table view data source reports the updated numberOfRows. I could not figure out an easy way around that so far.
Solution for xamarin.iOS:
ActionsTableView.TableFooterView = new UIView() { Frame = new CGRect(0, 0, ActionsTableView.Frame.Size.Width, 1) };
I am setting a footer view in the viewDidLoad method:
UIView *fView = [[UIView alloc] initWithFrame:CGRectMake(0, 718, 239, 50)];
fView.backgroundColor =[UIColor yellowColor];
self.table.tableFooterView = fView;
Unfortunately, the footer is not drawing in the specified (x,y) specified above, but it stick with the cells, so if the table view has 4 cells, the footer will be drawn in the 5th cell.
I even tried the protocol method, tableView:viewForFooterInSection
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{
UIView *fView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 239, 50)];
fView.backgroundColor =[UIColor yellowColor];
return fView;
}
the problem is not resolved, I am sure tableFooterView property should fi the footer view at the bottom of the table view but I am not sure what I may be missing here? Thanx in advance.
Since your goal is to have a footer that stays fixed at the bottom of the screen, and not scroll with the table, then you can't use a table view footer. In fact, you can't even use a UITableViewController.
You must implement your view controller as a UIViewController. Then you add your own table view as a subview. You also add your footer as a subview of the view controller's view, not the table view. Make sure you size the table view so its bottom is at the top of the footer view.
You will need to make your view controller conform to the UITableViewDataSource and UITableViewDelegate protocols and hook everything up to replicate the functionality of UITableViewController.
A footer view will always be added to the bottom of content.
This means that a section footer will be added below the cells of a section, a table footer view to the bottom of all sections - regardless of the position you set in your view.
If you want to add a "static" content, you should consider adding a view outside of the table view (superview) - which isn't possible if you use UITableViewController - or you use [self.table addSubView:view] and adjust the position/transform to the table view's contentOffset property in the scrollViewDidScroll: delegate method (UITableView is a subclass of UIScrollView so you also get it's delegate calls) like in this code:
#implementation YourTableViewController {
__weak UIView *_staticView;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIView *staticView = [[UIView alloc] initWithFrame:CGRectMake(0, self.tableView.bounds.size.height-50, self.tableView.bounds.size.width, 50)];
staticView.backgroundColor = [UIColor redColor];
[self.tableView addSubview:staticView];
_staticView = staticView;
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 50, 0);
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
_staticView.transform = CGAffineTransformMakeTranslation(0, scrollView.contentOffset.y);
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
// this is needed to prevent cells from being displayed above our static view
[self.tableView bringSubviewToFront:_staticView];
}
...
Another way is to use UITableViewController in a storyboard, and embed it within a UIViewController as a container view. Then you can use auto layout to set the relationship between the footer and the container view which contains the UITableView
If your table view or table view controller is wrapped by a navigation controller consider using the navigation controller's UIToolbar. It will always stick to the bottom.
[self.navigationController setToolbarHidden:NO];
It looks like something similar to below works quite well:
import PlaygroundSupport
import UIKit
let testVC = UITableViewController(style: .grouped)
testVC.view.frame = CGRect(x: 0, y: 0, width: 400, height: 700)
testVC.view.backgroundColor = .white
class TableViewDataSourceDelegate : NSObject {
var rows = 2
}
extension TableViewDataSourceDelegate : UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return rows
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
cell.backgroundColor = .red
return cell
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
let tableViewHeight = tableView.bounds.size.height
let varticalMargin: CGFloat
if #available(iOS 11.0, *) {
varticalMargin = tableView.directionalLayoutMargins.bottom + tableView.directionalLayoutMargins.top
} else {
varticalMargin = tableView.layoutMargins.bottom + tableView.layoutMargins.top
}
let verticalInset: CGFloat
if #available(iOS 11.0, *) {
verticalInset = tableView.adjustedContentInset.bottom + tableView.adjustedContentInset.top
} else {
verticalInset = tableView.contentInset.bottom + tableView.contentInset.top
}
let tableViewContentHeight = tableView.contentSize.height - varticalMargin
let height: CGFloat
if #available(iOS 11.0, *) {
let verticalSafeAreaInset = tableView.safeAreaInsets.bottom + tableView.safeAreaInsets.top
height = tableViewHeight - tableViewContentHeight - verticalInset - verticalSafeAreaInset
} else {
height = tableViewHeight - tableViewContentHeight - verticalInset
}
if (height < 0) {
return 0
} else {
return height
}
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let extraButtonSpace = UIView()
extraButtonSpace.backgroundColor = .clear
return extraButtonSpace
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
tableView.beginUpdates()
rows += 1
tableView.insertRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
} else if indexPath.row == 1 {
tableView.beginUpdates()
rows -= 1
tableView.deleteRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
} else {
tableView.beginUpdates()
tableView.endUpdates()
}
}
}
let controller = TableViewDataSourceDelegate()
testVC.tableView.delegate = controller
testVC.tableView.dataSource = controller
testVC.tableView.reloadData()
let extraButtonSpace = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 80))
extraButtonSpace.backgroundColor = .yellow
testVC.tableView.tableFooterView = extraButtonSpace
PlaygroundPage.current.liveView = testVC.view
I was able to get a label to be fixed to the bottom of my static UITableViewController. Not the perfect solution for all scenarios, but worked for my simple needs.
UIView* v = [[UIView alloc] initWithFrame:self.view.bounds];
CGFloat labelHeight = 30;
CGFloat padding = 5;
UILabel* l = [[UILabel alloc] initWithFrame:CGRectMake(0, v.frame.size.height - labelHeight - padding, self.view.frame.size.width, labelHeight)];
l.text = #"Hello World";
[v addSubview:l];
[self.tableView setBackgroundView:v];
If you want to make footer fixed at bottom, you should create custom footerView and change footer frame when tableView content size is changing:
-(void)changeCustomTableFooterYPositionWithTableFrame:(CGRect)tableFrame tableContentSize: (CGSize) tableContentSize {
CGFloat originalTableViewTopEdgeInset = self.tableView.contentInset.top;
CGFloat originalTableViewBottomEdgeInset = self.tableView.contentInset.bottom - self.tableFooterView.frame.size.height;
CGFloat footerViewYPositionByContentSize = tableContentSize.height;
CGFloat footerViewYPositionByTableSize = tableFrame.size.height - self.tableFooterView.frame.size.height - originalTableViewTopEdgeInset - originalTableViewBottomEdgeInset;
CGFloat tableFooterViewYPosition = MAX(footerViewYPositionByContentSize, footerViewYPositionByTableSize);
self.tableFooterView.frame = CGRectMake(self.tableFooterView.frame.origin.x, tableFooterViewYPosition, self.customTableFooterView.frame.size.width, self.customTableFooterView.frame.size.height);
}
To detect when contentSize was changed add observer to contentSize:
[self addObserver: self forKeyPath: #"tableView.contentSize" options: NSKeyValueObservingOptionNew + NSKeyValueObservingOptionOld context: ContentSizeContext];
Do not forget to change tableView.edgeInsets when insert footer:
self.tableView.contentInset = UIEdgeInsetsMake(self.tableView.contentInset.top, self.tableView.contentInset.left, self.tableView.contentInset.bottom + self.customTableFooterView.frame.size.height, self.tableView.contentInset.right);
You can see inherited class and example at the link below:
TableViewWithFooterAtBottom
You can use this to make the table look smaller according to how many rows do you have :
let tblView = UIView(frame: CGRectZero)
tableView.tableFooterView = tblView
tableView.tableFooterView!.hidden = true
tableView.backgroundColor = UIColor.clearColor()
Another alternative would be to just change the height for row at index path depending on for what number minimum rows you have that problem.
The following is the solution for this footer problem, when we do NOT want the footer to stick in the bottom all the time, AKA. it only sticks to the bottom when there are not enough rows to fill the screen, or when the user scrolls all the way down of the screen.
Add your self.footerView to your self.tableView as a subview on -viewDidLoad: or somewhere like that, then set the delegate for self.tableView, update the content inset of the tableview to self.tableView.contentInset = UIEdgeInsetsMake(0, 0, CGRectGetHeight(self.footerView), 0); and set up the following methods:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[self updateFooterView];
}
- (void)updateFooterView
{
CGRect sectionFrame = [self.tableView rectForSection:0];
CGFloat bottomSpace = self.tableView.contentOffset.y + CGRectGetHeight(self.tableView.frame) - CGRectGetMaxY(sectionFrame);
CGFloat footerHeight = CGRectGetHeight(self.footerView.frame);
CGFloat transformY = self.tableView.contentOffset.y + footerHeight - MIN(bottomSpace,footerHeight);
CGRect footerFrame = self.footerView.frame;
footerFrame.origin.y = self.tableView.bounds.size.height - footerFrame.size.height + transformY;
self.footerView.frame = footerFrame;
}
Whenever you need to update the footer (i.e. after adding a new row), just call -updateFooterView and you should be good
Im not super proud of this solution, but it worked for me using only IB as of today. It will use the toolbar area of your UITableViewController, if that works for you.
Create a new temporary UIViewController
Drag a Toolbar into this UIViewController
Drag a UIView on this toolbar. I used the elements tree on the left for that, was easier. This will create a BarButtonItem you'll move on step 5.
Drag a BarButtonItem on your UITableViewController, this will create a Toolbar items section.
Drag the BarButtonItem created on step 3 into the Toolbar items section created on step 4.
Delete the UIViewController and edit the BarButtonItem as you wish.
I want to customize UITableView header for each section. So far, I've implemented
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
this UITabelViewDelegate method. What I want to do is to get current header for each section and just add UILabel as a subview.
So far, I'm not able to accomplish that. Because, I couldn't find anything to get default section header. First question,is there any way to get default section header?
If it's not possible, I need to create a container view which is a UIView but,this time I need to set default background color,shadow color etc. Because, if you look carefully into section's header, it's already customized.
How can I get these default values for each section header?
You can try this:
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 18)];
/* Create custom view to display section header... */
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, tableView.frame.size.width, 18)];
[label setFont:[UIFont boldSystemFontOfSize:12]];
NSString *string =[list objectAtIndex:section];
/* Section header is in 0th index... */
[label setText:string];
[view addSubview:label];
[view setBackgroundColor:[UIColor colorWithRed:166/255.0 green:177/255.0 blue:186/255.0 alpha:1.0]]; //your background color...
return view;
}
The selected answer using tableView :viewForHeaderInSection: is correct.
Just to share a tip here.
If you are using storyboard/xib, then you could create another prototype cell and use it for your "section cell". The code to configure the header is similar to how you configure for row cells.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
static NSString *HeaderCellIdentifier = #"Header";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:HeaderCellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:HeaderCellIdentifier];
}
// Configure the cell title etc
[self configureHeaderCell:cell inSection:section];
return cell;
}
Swift version of Lochana Tejas answer:
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView(frame: CGRectMake(0, 0, tableView.frame.size.width, 18))
let label = UILabel(frame: CGRectMake(10, 5, tableView.frame.size.width, 18))
label.font = UIFont.systemFontOfSize(14)
label.text = list.objectAtIndex(indexPath.row) as! String
view.addSubview(label)
view.backgroundColor = UIColor.grayColor() // Set your background color
return view
}
If you use default header view you can only change the text on it with
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
For Swift:
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
If you want to customize the view you need to create a new one your self.
why not use UITableViewHeaderFooterView?
If headerInSection isn't show, can try this.
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 45;
}
This returns a height for the header of a given section.
Swift 3 version of lochana and estemendoza answers:
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView(frame: CGRect(x:0, y:0, width:tableView.frame.size.width, height:18))
let label = UILabel(frame: CGRect(x:10, y:5, width:tableView.frame.size.width, height:18))
label.font = UIFont.systemFont(ofSize: 14)
label.text = "This is a test";
view.addSubview(label);
view.backgroundColor = UIColor.gray;
return view
}
Also, be advised that you ALSO have to implement:
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 100;
}
The other answers do a good job of recreating the default header view, but don't actually answer your main question:
is there any way to get default section header ?
There is a way - just implement tableView:willDisplayHeaderView:forSection: in your delegate. The default header view will be passed into the second parameter, and from there you can cast it to a UITableViewHeaderFooterView and then add/change subviews as you wish.
Obj-C
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
UITableViewHeaderFooterView *headerView = (UITableViewHeaderFooterView *)view;
// Do whatever with the header view... e.g.
// headerView.textLabel.textColor = [UIColor whiteColor]
}
Swift
override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int)
{
let headerView = view as! UITableViewHeaderFooterView
// Do whatever with the header view... e.g.
// headerView.textLabel?.textColor = UIColor.white
}
Try this......
override func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int)
{
// Background view is at index 0, content view at index 1
if let bgView = view.subviews[0] as? UIView
{
// do your stuff
}
view.layer.borderColor = UIColor.magentaColor().CGColor
view.layer.borderWidth = 1
}
This is the easiest solution possible. The following code can be used directly for creating a custom section header.
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
SectionHeaderTableViewCell *headerView = [tableView dequeueReusableCellWithIdentifier:#"sectionHeader"];
//For creating a drop menu of rows from the section
//==THIS IS JUST AN EXAMPLE. YOU CAN REMOVE THIS IF-ELSE.==
if (![self.sectionCollapsedArray[section] boolValue])
{
headerView.imageView.image = [UIImage imageNamed:#"up_icon"];
}
else
{
headerView.imageView.image = [UIImage imageNamed:#"drop_icon"];
}
//For button action inside the custom cell
headerView.dropButton.tag = section;
[headerView.dropButton addTarget:self action:#selector(sectionTapped:) forControlEvents:UIControlEventTouchUpInside];
//For removing long touch gestures.
for (UIGestureRecognizer *recognizer in headerView.contentView.gestureRecognizers)
{
[headerView.contentView removeGestureRecognizer:recognizer];
[headerView removeGestureRecognizer:recognizer];
}
return headerView.contentView;
}
NOTE: SectionHeaderTableViewCell is a custom UITableViewCell created in Storyboard.
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
//put your values, this is part of my code
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 30.0f)];
[view setBackgroundColor:[UIColor redColor]];
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(20, 5, 150, 20)];
[lbl setFont:[UIFont systemFontOfSize:18]];
[lbl setTextColor:[UIColor blueColor]];
[view addSubview:lbl];
[lbl setText:[NSString stringWithFormat:#"Section: %ld",(long)section]];
return view;
}
Full 2019 example to copy and paste
First set "Grouped" on storyboard: it has to happen at init time, you can't really set it later, so it's easier to remember to do it on storyboard:
Next,
Must implement heightForHeaderInSection due to Apple bug.
func tableView(_ tableView: UITableView,
heightForHeaderInSection section: Int) -> CGFloat {
return CGFloat(70.0)
}
There is still an Apple bug - for ten years now - where it simply won't show the first header (i.e., index 0) if you don't have heightForHeaderInSection call.
So, tableView.sectionHeaderHeight = 70 simply doesn't work, it's broken.
Setting a frame achieves nothing:
In viewForHeaderInSection simply create a UIView().
It is pointless / achieves nothing if you UIView(frame ...) since iOS simply sets the size of the view as determined by the table.
So the first line of viewForHeaderInSection will be simply let view = UIView() and that is the view you return.
func tableView(_ tableView: UITableView,
viewForHeaderInSection section: Int) -> UIView? {
let view = UIView()
let l = UILabel()
view.addSubview(l)
l.bindEdgesToSuperview()
l.backgroundColor = .systemOrange
l.font = UIFont.systemFont(ofSize: 15)
l.textColor = .yourClientsFavoriteColor
switch section {
case 0:
l.text = "First section on screen"
case 1:
l.text = "Here's the second section"
default:
l.text = ""
}
return view
}
That's it - anything else is a time waste.
Another "fussy" Apple issue.
The convenience extension used above is:
extension UIView {
// incredibly useful:
func bindEdgesToSuperview() {
guard let s = superview else {
preconditionFailure("`superview` nil in bindEdgesToSuperview")
}
translatesAutoresizingMaskIntoConstraints = false
leadingAnchor.constraint(equalTo: s.leadingAnchor).isActive = true
trailingAnchor.constraint(equalTo: s.trailingAnchor).isActive = true
topAnchor.constraint(equalTo: s.topAnchor).isActive = true
bottomAnchor.constraint(equalTo: s.bottomAnchor).isActive = true
}
}
If I were you, I would make a method which returns an UIView given a NSString to contain. For example
+ (UIView *) sectionViewWithTitle:(NSString *)title;
In the implementation of this method create a UIView, add a UILabel to it with the properties you want to set, and of course set its title to the given one.
#samwize's solution in Swift (so upvote him!). Brilliant using same recycling mechanism also for header/footer sections:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let settingsHeaderSectionCell:SettingsHeaderSectionCell = self.dequeueReusableCell(withIdentifier: "SettingsHeaderSectionCell") as! SettingsHeaderSectionCell
return settingsHeaderSectionCell
}
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
if([view isKindOfClass:[UITableViewHeaderFooterView class]]){
UITableViewHeaderFooterView *headerView = view;
[[headerView textLabel] setTextColor:[UIColor colorWithHexString:#"666666"]];
[[headerView textLabel] setFont:[UIFont fontWithName:#"fontname" size:10]];
}
}
If you want to change the font of the textLabel in your section header you want to do it in willDisplayHeaderView. To set the text you can do it in viewForHeaderInSection or titleForHeaderInSection. Good luck!
Magically add Table View Header in swift
Recently I tried this.
I needed one and only one header in the whole UITableView.
Like I wanted a UIImageView on the top of the TableView. So I added a UIImageView on top of the UITableViewCell and automatically it was added as a tableViewHeader. Now I connect the ImageView to the ViewController and added the Image.
I was confused because I did something like this for the first time. So to clear my confusion open the xml format of the MainStoryBoard and found the Image View was added as a header.
It worked for me. Thanks xCode and swift.
call this delegate method
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
return #"Some Title";
}
this will give a chance to automatically add a default header with dynamic title .
You may use reusable and customizable header / footer .
https://github.com/sourov2008/UITableViewCustomHeaderFooterSection
swif 4.2
override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
guard let header = view as? UITableViewHeaderFooterView else { return }
header.textLabel?.textAlignment = .center // for all sections
switch section {
case 1: //only section No.1
header.textLabel?.textColor = .black
case 3: //only section No.3
header.textLabel?.textColor = .red
default: //
header.textLabel?.textColor = .yellow
}
}
besides to titleForHeaderInSection, you can simply change view of header, footer.
check my comment here: Change UITable section backgroundColor without loosing section Title
If you just want to add title to the tableView header dont add a view. In swift 3.x the code goes like this:
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
var lblStr = ""
if section == 0 {
lblStr = "Some String 1"
}
else if section == 1{
lblStr = "Some String 2"
}
else{
lblStr = "Some String 3"
}
return lblStr
}
You may implement an array to fetch the title for the headers.
Going back to the original question (4 years later), rather than rebuilding your own section header, iOS can simply call you (with willDisplayHeaderView:forSection:) right after it's built the default one. For example, I wanted to add a graph button on right edge of section header:
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section {
UITableViewHeaderFooterView * header = (UITableViewHeaderFooterView *) view;
if (header.contentView.subviews.count > 0) return; //in case of reuse
CGFloat rightEdge = CGRectGetMaxX(header.contentView.bounds);
UIButton * button = [[UIButton alloc] initWithFrame:CGRectMake(rightEdge - 44, 0, 44, CGRectGetMaxY(header.contentView.bounds))];
[button setBackgroundImage:[UIImage imageNamed:#"graphIcon"] forState:UIControlStateNormal];
[button addTarget:self action:#selector(graphButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
[view addSubview:button];
}
Use tableView: willDisplayHeaderView: to customize the view when it is about to be displayed.
This gives you the advantage of being able to take the view that was already created for the header view and extend it, instead of having to recreate the whole header view yourself.
Here is an example that colors the header section based on a BOOL and adds a detail text element to the header.
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
// view.tintColor = [UIColor colorWithWhite:0.825 alpha:1.0]; // gray
// view.tintColor = [UIColor colorWithRed:0.825 green:0.725 blue:0.725 alpha:1.0]; // reddish
// view.tintColor = [UIColor colorWithRed:0.925 green:0.725 blue:0.725 alpha:1.0]; // pink
// Conditionally tint the header view
BOOL isMyThingOnOrOff = [self isMyThingOnOrOff];
if (isMyThingOnOrOff) {
view.tintColor = [UIColor colorWithRed:0.725 green:0.925 blue:0.725 alpha:1.0];
} else {
view.tintColor = [UIColor colorWithRed:0.925 green:0.725 blue:0.725 alpha:1.0];
}
/* Add a detail text label (which has its own view to the section header… */
CGFloat xOrigin = 100; // arbitrary
CGFloat hInset = 20;
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(xOrigin + hInset, 5, tableView.frame.size.width - xOrigin - (hInset * 2), 22)];
label.textAlignment = NSTextAlignmentRight;
[label setFont:[UIFont fontWithName:#"Helvetica-Bold" size:14.0]
label.text = #"Hi. I'm the detail text";
[view addSubview:label];
}
Swift 4.2
In Swift 4.2 the name of table is a little changed.
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: 18))
let label = UILabel(frame: CGRect(x: 10, y: 5, width: tableView.frame.size.width, height: 18))
label.font = UIFont.systemFont(ofSize: 14)
label.text = list.objectAtIndex(section) as! String
view.addSubview(label)
view.backgroundColor = UIColor.gray // Set your background color
return view
}
Code for Swift 5
We can implement this by using two tableView delegate functions:
1] We can give custom height for the section:
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 49
}
2] Then we can create custom header:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let sectionV = UIView.init(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 48) )
let titleLbl = UILabel.init(frame: CGRect(x: 25, y: 24, width: tableView.frame.width-150, height: 20) )
let viewAllBtn = UIButton.init(frame: CGRect(x: tableView.frame.width-150, y: 15, width: self.view.frame.width - titleLbl.frame.width, height: 45))
viewAllBtn.titleLabel?.font = UIFont.systemFont(ofSize: 15)
viewAllBtn.setTitle("View All", for: .normal)
viewAllBtn.setTitleColor(.systemBlue, for: .normal)
viewAllBtn.tag = section
titleLbl.text = dashboardTempData.data?[section].title
titleLbl.font = UIFont.systemFont(ofSize: 21, weight: UIFont.Weight.medium)
sectionV.backgroundColor = .systemBackground
sectionV.addSubview(titleLbl)
sectionV.addSubview(viewAllBtn)
sectionV.bringSubviewToFront(viewAllBtn)
return sectionV
}
It will create a Label and Button with a section header height of 49
I have created a custom UITableViewCell. The table view is showing data fine. What I am stuck in is when user touches cell of tableview, then I want to show the background color of the cell other than the default [blue color] values for highlighting the selection of cell.
I use this code but nothing happens:
cell.selectedBackgroundView.backgroundColor=[UIColor blackColor];
No need for custom cells. If you only want to change the selected color of the cell, you can do this:
Objective-C:
UIView *bgColorView = [[UIView alloc] init];
bgColorView.backgroundColor = [UIColor redColor];
[cell setSelectedBackgroundView:bgColorView];
Swift:
let bgColorView = UIView()
bgColorView.backgroundColor = UIColor.red
cell.selectedBackgroundView = bgColorView
I think you were on the right track, but according to the class definition for selectedBackgroundView:
The default is nil for cells in plain-style tables (UITableViewStylePlain) and non-nil for section-group tables UITableViewStyleGrouped).
Therefore, if you're using a plain-style table, then you'll need to alloc-init a new UIView having your desired background colour and then assign it to selectedBackgroundView.
Alternatively, if all you wanted was a gray background when the cell is selected, you could use this:
cell.selectionStyle = UITableViewCellSelectionStyleGray;
Table View Cell selection background color can be set via the Storyboard in Interface Builder:
If you have a grouped table with just one cell per section, just add this extra line to the code:
bgColorView.layer.cornerRadius = 10;
UIView *bgColorView = [[UIView alloc] init];
[bgColorView setBackgroundColor:[UIColor redColor]];
bgColorView.layer.cornerRadius = 10;
[cell setSelectedBackgroundView:bgColorView];
[bgColorView release];
Don't forget to import QuartzCore.
Swift 3: for me it worked when you put it in the cellForRowAtIndexPath: method
let view = UIView()
view.backgroundColor = UIColor.red
cell.selectedBackgroundView = view
The following works for me in iOS 8.
I have to set the selection style to UITableViewCellSelectionStyleDefault for custom background color to work. If any other style, the custom background color will be ignored. There seems to be a change in behaviours as previous answers needs to set style to none instead.
The full code for the cell as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"MyCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// This is how you change the background color
cell.selectionStyle = UITableViewCellSelectionStyleDefault;
UIView *bgColorView = [[UIView alloc] init];
bgColorView.backgroundColor = [UIColor redColor];
[cell setSelectedBackgroundView:bgColorView];
return cell;
}
Create a custom cell for your table cell and in the custom cell class.m put the code below, it will work fine. You need to place the desired color image in selectionBackground UIImage.
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
UIImage *selectionBackground = [UIImage imageNamed:#"yellow_bar.png"];
UIImageView *iview=[[UIImageView alloc] initWithImage:selectionBackground];
self.selectedBackgroundView=iview;
}
Swift 3.0 extension
extension UITableViewCell {
var selectionColor: UIColor {
set {
let view = UIView()
view.backgroundColor = newValue
self.selectedBackgroundView = view
}
get {
return self.selectedBackgroundView?.backgroundColor ?? UIColor.clear
}
}
}
cell.selectionColor = UIColor.FormaCar.blue
In Swift 4, you can also set the background color of your table cell globally (taken from here):
let backgroundColorView = UIView()
backgroundColorView.backgroundColor = UIColor.red
UITableViewCell.appearance().selectedBackgroundView = backgroundColorView
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
UIView *view = [[UIView alloc] init];
[view setBackgroundColor:[UIColor redColor]];
[cell setSelectedBackgroundView:view];
}
We need to set the selected background view in this method.
Swift 4+:
Add following lines in your table cell
let bgColorView = UIView()
bgColorView.backgroundColor = .red
self.selectedBackgroundView = bgColorView
Finally it should be as below
override func setSelected(_ selected: Bool, animated: Bool)
{
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
let bgColorView = UIView()
bgColorView.backgroundColor = .red
self.selectedBackgroundView = bgColorView
}
If you want to add a custom highlighted color to your cell (and your cell contains buttons,labels, images,etc..) I followed the next steps:
For example if you want a selected yellow color:
1) Create a view that fits all the cell with 20% opacity (with yellow color) called for example backgroundselectedView
2) In the cell controller write this:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
self.backgroundselectedView.alpha=1;
[super touchesBegan:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
self.backgroundselectedView.alpha=0;
[super touchesEnded:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
self.backgroundSelectedImage.alpha=0;
[super touchesCancelled:touches withEvent:event];
}
If you are using a custom TableViewCell, you can also override awakeFromNib:
override func awakeFromNib() {
super.awakeFromNib()
// Set background color
let view = UIView()
view.backgroundColor = UIColor.redColor()
selectedBackgroundView = view
}
I want to note that the XIB editor offers you the following standard options:
Section: blue/gray/none
(the right-hand column with options, 4th tab, first group "Table View Cell", 4th subgroup, the 1st of 3 items reads "Selection")
Probably what you want to do may be achieved by selecting the right standard option.
One more tip to Christian's way to show rounded corner background for grouped table.
If I use cornerRadius = 10 for cell, it shows four corner's rounded selection background. It's not the same with table view's default UI.
So, I think about easy way to resolve it with cornerRadius.
As you can see from the below codes, check about cell's location (top, bottom, middle or topbottom) and add one more sub layers to hide top corner or bottom corner. This just shows exactly same look with default table view's selection background.
I tested this code with iPad splitterview. You can change patchLayer's frame position as you needed.
Please let me know if there is more easier way to achieve same result.
if (tableView.style == UITableViewStyleGrouped)
{
if (indexPath.row == 0)
{
cellPosition = CellGroupPositionAtTop;
}
else
{
cellPosition = CellGroupPositionAtMiddle;
}
NSInteger numberOfRows = [tableView numberOfRowsInSection:indexPath.section];
if (indexPath.row == numberOfRows - 1)
{
if (cellPosition == CellGroupPositionAtTop)
{
cellPosition = CellGroupPositionAtTopAndBottom;
}
else
{
cellPosition = CellGroupPositionAtBottom;
}
}
if (cellPosition != CellGroupPositionAtMiddle)
{
bgColorView.layer.cornerRadius = 10;
CALayer *patchLayer;
if (cellPosition == CellGroupPositionAtTop)
{
patchLayer = [CALayer layer];
patchLayer.frame = CGRectMake(0, 10, 302, 35);
patchLayer.backgroundColor = YOUR_BACKGROUND_COLOR;
[bgColorView.layer addSublayer:patchLayer];
}
else if (cellPosition == CellGroupPositionAtBottom)
{
patchLayer = [CALayer layer];
patchLayer.frame = CGRectMake(0, 0, 302, 35);
patchLayer.backgroundColor = YOUR_BACKGROUND_COLOR;
[bgColorView.layer addSublayer:patchLayer];
}
}
}
As per custom color for a selected cell in UITableView, great solution as per Maciej Swic's answer
Just to add to that, you declare Swic's answer in the Cell configuration usually under:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
And for an added effect, instead of the system colors, you may use RGB values for a custom color look. In my code this is how I achieved it:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
}
static NSString *CellIdentifier = #"YourCustomCellName";
MakanTableCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
if (cell == nil) {
cell = [[[NSBundle mainBundle]loadNibNamed:#"YourCustomCellClassName" owner:self options:nil]objectAtIndex:0];
}
UIView *bgColorView = [[UIView alloc] init];
bgColorView.backgroundColor = [UIColor colorWithRed:255.0/256.0 green:239.0/256.0 blue:49.0/256.0 alpha:1];
bgColorView.layer.cornerRadius = 7;
bgColorView.layer.masksToBounds = YES;
[cell setSelectedBackgroundView:bgColorView];
return cell;
}
Let me know if that works for you as well. You can mess with the cornerRadius number for the effects on the corners of the selected cell.
To add the background for all cells (using Maciej's answer):
for (int section = 0; section < [self.tableView numberOfSections]; section++) {
for (int row = 0; row < [self.tableView numberOfRowsInSection:section]; row++) {
NSIndexPath* cellPath = [NSIndexPath indexPathForRow:row inSection:section];
UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:cellPath];
//stuff to do with each cell
UIView *bgColorView = [[UIView alloc] init];
bgColorView.backgroundColor = [UIColor redColor];
[cell setSelectedBackgroundView:bgColorView];
}
}
I've got a slightly different approach than everyone else that reflects the selection on touch rather than after being selected. I have a subclassed UITableViewCell. All you have to do is set the background color in the touch events, which simulates selection on touch, and then set the background color in the setSelected function. Setting the background color in the selSelected function allows for deselecting the cell. Make sure to pass the touch event to the super, otherwise the cell won't actually act as if its selected.
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.backgroundColor = UIColor(white: 0.0, alpha: 0.1)
super.touchesBegan(touches, withEvent: event)
}
override func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!) {
self.backgroundColor = UIColor.clearColor()
super.touchesCancelled(touches, withEvent: event)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
self.backgroundColor = selected ? UIColor(white: 0.0, alpha: 0.1) : UIColor.clearColor()
}
To override UITableViewCell's setSelected also works.
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Set background color
let view = UIView()
view.backgroundColor = UIColor.redColor()
selectedBackgroundView = view
}
for those that just want to get rid of the default selected grey background put this line of code in your cellForRowAtIndexPath func:
yourCell.selectionStyle = .None
for Swift 3.0:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = super.tableView(tableView, cellForRowAt: indexPath)
cell.contentView.backgroundColor = UIColor.red
}
I use below approach and works fine for me,
class MyTableViewCell : UITableViewCell {
var defaultStateColor:UIColor?
var hitStateColor:UIColor?
override func awakeFromNib(){
super.awakeFromNib()
self.selectionStyle = .None
}
// if you are overriding init you should set selectionStyle = .None
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let hitColor = hitStateColor {
self.contentView.backgroundColor = hitColor
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let defaultColor = defaultStateColor {
self.contentView.backgroundColor = defaultColor
}
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
if let defaultColor = defaultStateColor {
self.contentView.backgroundColor = defaultColor
}
}
}
1- Add a view to the content view of your cell.
2- Right click your cell.
3- Make the added view as "selectedBackgroundView".
Here is the important parts of the code needed for a grouped table. When any of the cells in a section are selected the first row changes color. Without initially setting the cellselectionstyle to none there is an annonying double reload when the user clicks row0 where the cell changes to bgColorView then fades and reloads bgColorView again. Good Luck and let me know if there is a simpler way to do this.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if ([indexPath row] == 0)
{
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UIView *bgColorView = [[UIView alloc] init];
bgColorView.layer.cornerRadius = 7;
bgColorView.layer.masksToBounds = YES;
[bgColorView setBackgroundColor:[UIColor colorWithRed:.85 green:0 blue:0 alpha:1]];
[cell setSelectedBackgroundView:bgColorView];
UIColor *backColor = [UIColor colorWithRed:0 green:0 blue:1 alpha:1];
cell.backgroundColor = backColor;
UIColor *foreColor = [UIColor colorWithWhite:1 alpha:1];
cell.textLabel.textColor = foreColor;
cell.textLabel.text = #"row0";
}
else if ([indexPath row] == 1)
{
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UIColor *backColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:1];
cell.backgroundColor = backColor;
UIColor *foreColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:1];
cell.textLabel.textColor = foreColor;
cell.textLabel.text = #"row1";
}
else if ([indexPath row] == 2)
{
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UIColor *backColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:1];
cell.backgroundColor = backColor;
UIColor *foreColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:1];
cell.textLabel.textColor = foreColor;
cell.textLabel.text = #"row2";
}
return cell;
}
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSIndexPath *path = [NSIndexPath indexPathForRow:0 inSection:[indexPath section]];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:path];
[cell setSelectionStyle:UITableViewCellSelectionStyleBlue];
[tableView selectRowAtIndexPath:path animated:YES scrollPosition:UITableViewScrollPositionNone];
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tvStat cellForRowAtIndexPath:indexPath];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}
#pragma mark Table view Gestures
-(IBAction)singleTapFrom:(UIGestureRecognizer *)tapRecog
{
CGPoint tapLoc = [tapRecog locationInView:tvStat];
NSIndexPath *tapPath = [tvStat indexPathForRowAtPoint:tapLoc];
NSIndexPath *seleRow = [tvStat indexPathForSelectedRow];
if([seleRow section] != [tapPath section])
[self tableView:tvStat didDeselectRowAtIndexPath:seleRow];
else if (seleRow == nil )
{}
else if([seleRow section] == [tapPath section] || [seleRow length] != 0)
return;
if(!tapPath)
[self.view endEditing:YES];
[self tableView:tvStat didSelectRowAtIndexPath:tapPath];
}
[cell setSelectionStyle:UITableViewCellSelectionStyleGray];
Make sure you have used the above line to use the selection effect
override func setSelected(selected: Bool, animated: Bool) {
// Configure the view for the selected state
super.setSelected(selected, animated: animated)
let selView = UIView()
selView.backgroundColor = UIColor( red: 5/255, green: 159/255, blue:223/255, alpha: 1.0 )
self.selectedBackgroundView = selView
}
In case of custom cell class. Just override:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
if (selected) {
[self setBackgroundColor: CELL_SELECTED_BG_COLOR];
[self.contentView setBackgroundColor: CELL_SELECTED_BG_COLOR];
}else{
[self setBackgroundColor: [UIColor clearColor]];
[self.contentView setBackgroundColor: [UIColor clearColor]];
}
}
It's easy when the table view style is plain, but in group style, it's a little trouble, I solve it by:
CGFloat cellHeight = [self tableView:tableView heightForRowAtIndexPath:indexPath];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kGroupTableViewCellWidth+2, cellHeight)];
view.backgroundColor = kCommonHighlightedColor;
cell.selectedBackgroundView = view;
[view release];
UIRectCorner cornerFlag = 0;
CGSize radii = CGSizeMake(0, 0);
NSInteger theLastRow = --> (yourDataSourceArray.count - 1);
if (indexPath.row == 0) {
cornerFlag = UIRectCornerTopLeft | UIRectCornerTopRight;
radii = CGSizeMake(10, 10);
} else if (indexPath.row == theLastRow) {
cornerFlag = UIRectCornerBottomLeft | UIRectCornerBottomRight;
radii = CGSizeMake(10, 10);
}
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:cornerFlag cornerRadii:radii];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = maskPath.CGPath;
view.layer.mask = shapeLayer;
noted the kGroupTableViewCellWidth, I define it as 300, it's the width of group table view cell width in iPhone
I'm using iOS 9.3 and setting the color through the Storyboard or setting cell.selectionStyle didn't work for me, but the code below worked:
UIView *customColorView = [[UIView alloc] init];
customColorView.backgroundColor = [UIColor colorWithRed:55 / 255.0
green:141 / 255.0
blue:211 / 255.0
alpha:1.0];
cell.selectedBackgroundView = customColorView;
return cell;
I found this solution here.
Try Following code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[cellIdArray objectAtIndex:indexPath.row] forIndexPath:indexPath];
// Configure the cell...
cell.backgroundView =
[[UIImageView alloc] init] ;
cell.selectedBackgroundView =[[UIImageView alloc] init];
UIImage *rowBackground;
UIImage *selectionBackground;
rowBackground = [UIImage imageNamed:#"cellBackgroundDarkGrey.png"];
selectionBackground = [UIImage imageNamed:#"selectedMenu.png"];
((UIImageView *)cell.backgroundView).image = rowBackground;
((UIImageView *)cell.selectedBackgroundView).image = selectionBackground;
return cell;
}
//Swift Version:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")! as UITableViewCell
cell.selectedBackgroundView = UIImageView()
cell.backgroundView=UIImageView()
let selectedBackground : UIImageView = cell.selectedBackgroundView as! UIImageView
selectedBackground.image = UIImage.init(named:"selected.png");
let backGround : UIImageView = cell.backgroundView as! UIImageView
backGround.image = UIImage.init(named:"defaultimage.png");
return cell
}