Adjust UITableViewCell separator line when in multiple edit mode - ios

I'm looking to adjust the separator inset margin when in multiple edit mode in a standard UITableView in iOS 9/10.
My goal is to align the separator line with the left edge of the cell's text label.
In the past, I've removed the margins entirely by doing:
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.separatorInset = .zero
cell.layoutMargins = .zero
}
That gives me a view such as:
If I try to increase the separator inset, the entire text label moves over, which I don't want. :
cell.separatorInset = UIEdgeInsetsMake(0, 40, 0, 0)
How can I just move the separator line, without affecting the text layout, and preferably without doing any overriding of layoutSubviews or drawing lines manually?

You can add separator manually, try to use below code
func viewDidLoad() {
self.tableview.separatorStyle = UITableViewCellSeparatorStyle.None
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let separator = CALayer()
separator.backgroundColor = UIColor.grayColor();
separator.frame = CGRectMake(0, 43, self.view.frame.size.width, 1);
cell.layer.insertSublayer(separator, atIndex:0)
return cell;
}

I'm on xcode 8, with ios 9
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
cell.layoutMargins = .zero
}
gives you the what you want as per your third picture.
I've tried
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
cell.layoutMargins = .zero
}
it works too, not sure why its not working on your side..

Related

Self sizing cells height change causes jumping animation

I have setup a tableview with dynamic height cells aka UITableView.automaticDimension using Autolayout. This works fine. Now what I am trying to achieve is to change the height of cell & animate it. The issue is that when I change cell height & animate it, the animation is weirdly jumping. The jump only occurs if I scroll down a bit & then expand/collapse cells.
I have a simple table view cell. It has a label & an empty UIView with fixed height constraint. When I want to collapse/expand the cell, I simply change the constant of that height constraint to 0 or 300.
I have tried many collapsable tableview examples off the internet. All of them have this issue. One exception is https://github.com/Ramotion/folding-cell, but that uses fixed heights for cells.
I have tried quite a few options to animate the cell height change.
1-> On didSelectRow, I change the height constraint & call tableview beginUpdate & endUpdates. Doesn't solve the jump issue.
2-> Change my model & call tableView.reloadRows. Doesn't solve the jump issue.
This is screenshot of my tableview cell setup.
https://drive.google.com/open?id=12nba6cwRszxRlaSA-IhrX3X_vLZ4AWxy
A link to video of this issue:
https://drive.google.com/open?id=19Xmc0PMXT0EuHTJeeGHm4M5aPoChAtf3
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
tableView.estimatedRowHeight = 50
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedSectionHeaderHeight = 0
tableView.estimatedSectionFooterHeight = 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! OuterTableViewCell
let height: CGFloat = isCellExpanded[indexPath.row] ? 300 : 0
cell.labelText.text = "Cell Number: \(indexPath.row + 1)"
cell.buttonExpansionToggle.setImage(UIImage(named: isCellExpanded[indexPath.row] ? "arrow-down" : "arrow-right"),
for: .normal)
cell.viewContainerHeight.constant = height
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
isCellExpanded[indexPath.row] = !isCellExpanded[indexPath.row]
tableView.reloadRows(at: [indexPath], with: .automatic)
}
Another form of didSelectRow:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) as? OuterTableViewCell else { return }
isCellExpanded[indexPath.row] = !isCellExpanded[indexPath.row]
let height: CGFloat = self.isCellExpanded[indexPath.row] ? 300 : 0
cell.viewContainerHeight.constant = height
cell.layoutIfNeeded()
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseOut, animations: {
tableView.beginUpdates()
tableView.endUpdates()
// fix https://github.com/Ramotion/folding-cell/issues/169
if cell.frame.maxY > tableView.frame.maxY {
tableView.scrollToRow(at: indexPath, at: UITableView.ScrollPosition.bottom, animated: true)
}
}, completion: nil)
}
I have also tried to call beginUpdates() & endUpdates() outside animation block, yet the issue persists.
I expect the animation to be smooth. Hope someone can help. If someone can setup a simple demo project on github that would be awesome.
Demo project link: https://gitlab.com/FahadMasoodP/nested-tableviews
Help in any form is appreciated. Thanks.
My solution is adding dynamic estimate row height. I think it is bug of UIKit. iOS 13 issue will be not occur.
First, You need add property estimateRowHeightStorage to store estimate height by indexpath
var estimateRowHeightStorage: [IndexPath:CGFloat] = [:]
Second, You need store current height of cell for use later
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
estimateRowHeightStorage[indexPath] = cell.frame.size.height
}
Final, you use estimateRowHeightStorage to set estimate row height.
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if estimateRowHeightStorage[indexPath] != nil {
return estimateRowHeightStorage[indexPath]!
}
return 50
}
Run and feel.
I did found new solution in your case. If you hardfix height when expand. Only need change some thing.
Replace all code above with estimatedHeightForRowAt function
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
let height: CGFloat = isCellExpanded[indexPath.row] ? 373 : 73
return height
}

UITableViewCell frame margins in Swift

I want to enter cell coordinates. When I apply the following code, the cell disappears from the application. How do I adjust the frame margin?
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
cell.layoutMargins = UIEdgeInsets(top: 50, left: 25, bottom: 0, right: 25)
cell.preservesSuperviewLayoutMargins = false
}
For cells, try this:
override func tableView(tableView: UITableView,
willDisplayCell cell: UITableViewCell,
forRowAtIndexPath indexPath: NSIndexPath)
{
cell.separatorInset = UIEdgeInsetsZero
cell.preservesSuperviewLayoutMargins = false
cell.layoutMargins = UIEdgeInsetsZero
}
But based on the edited information, it seems that you have margin in the container view of the table view. Either this comes from your constraints between table view and view (check them one by one) or you have layout margins in the view, in which case try;
override func viewDidLoad() {
// ...
self.view.layoutMargins = UIEdgeInsetsZero
}
You need to set the row height to be the sum of the desired content height plus the desired margin height.
If all rows are the same height, set the rowHeight property of the table view to a number that is big enough for your needed content height plus the desired top and bottom margin.
If each row is a different height, then implement the heightForRowAt delegate method and return the needed total height (including margin).

UITableView row separator cut off when updating cell

I have a grouped UITableView in which I display some car data in the second section. I load the image from a web server using SDWebImage. In its callback I resize the picture and update my image view.
However, as soon as I update my image view, the UITableView separator is cut off.
For illustration purposes I've given the respective elements background colors
When the image is not loaded yet, it looks like this:
When the image is updated, it looks like this
Notice that the row separator is somehow cut off between the UITableView cells even though no subview (the UIImageView) is hiding it.
Depending on the UITableView section the row height varies, so I've overwritten the heightForRowAtIndexPath UITableView delegate
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.section == 0 {
return GFFloat(44)
}
else {
return CGFloat(220)
}
}
Can someone tell me why the separators disappear and how I can fix this? I've read about reloading the next UITableViewCell when I update the image, but since I display a lot of cars, my app crashes when I try this.
Just add below method it will resolve separator issue.
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if cell.respondsToSelector("setSeparatorInset:") {
cell.separatorInset = UIEdgeInsetsZero
}
if cell.respondsToSelector("setPreservesSuperviewLayoutMargins:") {
cell.preservesSuperviewLayoutMargins = false
}
if cell.respondsToSelector("setLayoutMargins:") {
cell.layoutMargins = UIEdgeInsetsZero
}
}
Solution for Swift 5
Add this to your controller:
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if cell.responds(to: #selector(setter: UITableViewCell.separatorInset)) {
cell.separatorInset = UIEdgeInsets.zero
}
if cell.responds(to: #selector(setter: UIView.preservesSuperviewLayoutMargins)) {
cell.preservesSuperviewLayoutMargins = false
}
if cell.responds(to: #selector(setter: UIView.layoutMargins)) {
cell.layoutMargins = UIEdgeInsets.zero
}
}

How to remove iOS TableView Separator

Hello, thanks for reading.
I 've tried to remove these separators since a while, it's horrible I can't delete them. I have tried a lot of answers in stackoverflow but no one was helpfull :/
Here is the problem :
I can't remove these white spaces between cells :s.
I've tried :
Change background color to same grey than cell,but it does not works
Checking cell size
Set separatorStyle to UITableViewCellSeparatorStyle.None
Returning the good height with tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
Disabling separator in main storyboard
... I really don't understand how to remove these white space ...
Sorry for my english,
Thanks
I'm adding this. Now you can check my settings : (And you can see separators are disabled)
you just need to change this in the Attribute inspector:
Try this tableView method:
override func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat
{
return 0.00001
}
Try this hope it will be help full to you.
Objective C :
-(CGFloat)tableView:(UITableView*)tableView heightForFooterInSection:(NSInteger)section
{
return 0.1f;
}
-(UIView*)tableView:(UITableView*)tableView viewForFooterInSection:(NSInteger)section
{
return [[UIView alloc] initWithFrame:CGRectZero] ;
}
Swift :
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
return UIView(frame: CGRectZero)
}
override func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 0.1f
}
set the tableviewcell separator none likewise the image http://imgur.com/MbVA7pM
Try this out:
func tableView(tableView: UITableView!, willDisplayCell cell: UITableViewCell!, forRowAtIndexPath indexPath: NSIndexPath!) {
// Remove seperator inset
if cell.respondsToSelector("setSeparatorInset:") {
cell.separatorInset = UIEdgeInsetsZero
}
// Prevent the cell from inheriting the Table View's margin settings
if cell.respondsToSelector("setPreservesSuperviewLayoutMargins:") {
cell.preservesSuperviewLayoutMargins = false
}
// Explictly set your cell's layout margins
if cell.respondsToSelector("setLayoutMargins:") {
cell.layoutMargins = UIEdgeInsetsZero
}
}
In swift hiding the table view separator
func tableView(tableView: UITableView!, willDisplayCell cell: UITableViewCell!, forRowAtIndexPath indexPath: NSIndexPath!)
{
cell.backgroundColor = UIColor.clearColor()
}
Ok I'm sorry, the problem was on my code, so you could not answer me ...
It was in my function : tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
Somewhere I wanted a border on my cell, so I have write:
var layer: CALayer = cell.layer
layer.borderColor = UIColor.rgbaColor(red: 288, green: 83, blue: 88, alpha: 1).CGColor
layer.borderWidth = 2
But this code didn't work because red:288 should be red:188, so I had a white border instead of an error, and I did not noticed ... Sorry for this, thanks a lot for your help :)
Just set the footer view to empty view:
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
so separator will disappear for empty cells (you still keep separator for normal cells).
In objective c
[self.tableView setSeparatorColor:[UIColor myColor]];
In Swift
tableView.separatorColor = UIColor.clear

UITableView checkmark style remove highlight on select

I am trying to remove the highlight when selecting a table view cell, but want to keep the checkmark that appears.
When I try this in cellForRowAtIndexPath:
cell.backgroundView = UIView()
cell.backgroundView?.backgroundColor = UIColor.clearColor()
It only removes the highlight underneath the checkmark, rather than the whole row (refer to image attached).
When I try this in cellForRowAtIndexPath:
cell.selectionStyle = UITableViewCellSelectionStyle.None
It no longer displays the checkmark.
UPDATE: tried this, does the same thing as cell.selectionStyle where it no longer does checkmark
func tableView(tableView: UITableView, shouldHighlightRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return false
}
What is a good way of doing this? I want it to still function like a checkbox but just don't want the blue highlighting to occur. TableView is dynamically generated:
checkBoxView = UITableView()
checkBoxView.frame = CGRect(x: qView.bounds.midX, y: qView.bounds.midY, width: qView.bounds.width - 100, height: qView.bounds.height/1.5)
checkBoxView.center = CGPointMake(qView.bounds.midX, qView.bounds.midY)
checkBoxView.delegate = self
checkBoxView.dataSource = self
checkBoxView.tag = 100
checkBoxView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
checkBoxView.setEditing(true, animated: true)
self.qView.addSubview(checkBoxView)
Table View Functions:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.checkBoxContent.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = checkBoxView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
cell.textLabel?.text = self.checkBoxContent[indexPath.row]
cell.backgroundColor = UIColor.clearColor()
cell.tintColor = UIColor.greenColor()
return cell
}
func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle {
return UITableViewCellEditingStyle(rawValue: 3)!
}
In order to keep the checkmark, you can't set false to this shouldHighlightRowAtIndexPath method. If you do so, this wouldn't even show the checkmark on the left hand side at all.
What i have done is changing the "selectedBackgroundView" of cell which would keep the left-hand side checkmark and giving me the chance to set the background color. I enclose some code here and hope it would help.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(cellID, forIndexPath: indexPath) as! RecordTableViewCell
cell.selectedBackgroundView = UIView(frame: cell.frame)
cell.selectedBackgroundView?.backgroundColor = UIColor.orangeColor()
return cell
}
None of the suggestions above worked for me. In Swift 5, add this line to your cellForRowAtIndexPath function:
cell.selectionStyle = UITableViewCell.SelectionStyle.none
Swift 1.2 use:
tableView.deselectRowAtIndexPath(indexPath, animated: true)
In the didSelectRowAtIndexPath delegate method.
Theres an official way to do this with a UITableView, which is to use this :
optional func tableView(_ tableView: UITableView, shouldHighlightRowAtIndexPath indexPath: NSIndexPath) -> Bool
If you return YES for this method, then the tableview will highlight a cell when it is clicked.
Also note if you dont want to use that, that you need to change the contentView.backgroundColor, rather than just the cell backgroundColor. But the highlighting route is the best one to go down.
Documentation here : https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableViewDelegate_Protocol/index.html#//apple_ref/occ/intfm/UITableViewDelegate/tableView:shouldHighlightRowAtIndexPath:

Resources