I have a UITableViewCell, drawn in Storyboard.
However, running it on simulator, it seems that there is white line in each cell divider as well header-cell divider.
A is Header in UITableViewCell
A11 - A13 is content in UITableViewCell
How to remove it? It seems I can't find any answer out there.
Update:
Solution here only moves the divider color to left with no margin and keeps the header divider persists. Is there any way to remove the white color for both header and cell without moving the divider line?
You could simply choose to set Separator for the tableview to "None". Then subclass the UITableviewCell and create the border by adding a CALayer as a sublayer to the cell at awakeFromNib.
Using Swift 4.X 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
}
}
Related
I'm trying to display on screen some logs through UiTableView and I want to set a red text color to those hasPrefix "root" as following :
var logList: [String] = []
...
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.logList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableview.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! ItemLogCell
cell.itemLogLabel.text = self.logList[indexPath.row]
print(indexPath.row)
print(self.logList[indexPath.row].hasPrefix("root"))
if (self.logList[indexPath.row].hasPrefix("root")) {
cell.itemLogLabel.textColor = UIColor.red
}
return cell
}
The problem is even when the prefix condition is false, text color become red and only for some row.
The more I scroll the more there are random red logs. How can I fix this ?
You can do something like this to reset the color of the other lines :
if (self.logList[indexPath.row].hasPrefix("root")) {
cell.itemLogLabel.textColor = UIColor.red
}
else {
cell.itemLogLabel.textColor = UIColor.white
}
Use instead different UITableViewDelegate callback for that
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let cell = cell as? ItemLogCell else { return }
print(indexPath.row)
print(self.logList[indexPath.row].hasPrefix("root"))
if (self.logList[indexPath.row].hasPrefix("root")) {
cell.itemLogLabel.textColor = UIColor.red
}
}
Because UITableViewCell is basically reusable. Imagine that you are seeing there are 6 cells in the screen, index 0 to 5. When you scroll to cell with index 6, the cell with index 0 will be hidden. TableView will not create a new UITableViewCell for the cell 6, it will waste the device's memory. Instead, tableview will dequeue the cell 0 and reuse it. So, cell 6 will has the default value of cell 0. To fix this issue, you will need to set the color again, of the cell that does not has prefix "root"
if (self.logList[indexPath.row].hasPrefix("root")) {
cell.itemLogLabel.textColor = UIColor.red
} else {
cell.itemLogLabel.textColor = UIColor.black
}
As pham hai explain cells are reusable so You should consider else case as well. Shorty
let cellColor = cell.itemLogLabel.textColor
self.logList[indexPath.row].hasPrefix("root") ? cellColor = .red : cellColor = .black
I set my tableview constraints pinch to left and right at zero in the storyboard.
But depends on my indexPath.row, I need to set new constraints (inset & width). I've tried this without success.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch dataType! {
case .mycase:
let cell = tableView.dequeueReusableCell(withIdentifier: "NoBrandDeviceFoundTableViewCell", for: indexPath) as! NoBrandDeviceFoundTableViewCell
tableView.isScrollEnabled = false
var frame = tableView.frame
frame.size.width = 343
cell.frame = frame
tableView.contentInset = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
return cell
}
}
The frame of the cell won't be changed it's been set equal to the width of the table , you can hook the leading/left & trailing/right constraints of the items you want to shift and change their constant's value according to that indexPath in cellForRowAt
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "NoBrandDeviceFoundTableViewCell", for: indexPath) as! NoBrandDeviceFoundTableViewCell
if indexPath.row == <#someValue#> {
cell.lblLeadingCon.constant = <#someValue#>
}
else {
cell.lblLeadingCon.constant = 0
}
return cell
}
you need to take cell leading constanint - nslcLeadingCell
you need to take cell trailing constatint - nslcTrailningCell
based on indexpathrow contion match you need make condition
if indexpath.row == 5
cell.nslcLeadingCell.constant = 10
cell.nslcTrailningCell.constanct = 15
I have a table view cell. I make an app for a tenant in the apartment to report the defect of the room facility. if the defect has been repaired (status: Complete), data from server will give defect.status == 2 (if defect.status == 1, still on process to be repaired), and it will show YES and NO Button like the picture above.
I want if it still on the repairment process, the view that contains "Are You satisfied" label and Yes No Button will not appear. The expected result should be like the picture below
here is the code I use to remove that satisfied or not view
extension RequestDefectVC : UITableViewDataSource {
//MARK: Table View Delegate & Datasource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listDefects.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "defectCell", for: indexPath) as! RequestDefectCell
let dataDefect = listDefects[indexPath.row]
cell.defectData = dataDefect
if dataDefect.status == 2 {
if let wantToRemoveView = cell.commentResponseView {
wantToRemoveView.removeFromSuperview()
}
}
return cell
}
}
but unfortunately, if that wantToRemoveView.removeFromSuperview() is triggered, it will remove all the view in all cell, even though the status is completed like picture below
I want that satisfied or not view appears if the status is complete, otherwise, it will be removed. how to do that ?
For your costumed cells are reused, removing views will cause uncertain effects. You don't actually need the specific view to be removed, only if it stays invisible.
if dataDefect.status == 2 {
if let wantToRemoveView = cell.commentResponseView {
wantToRemoveView.isHidden = true
}
} else {
if let wantToRemoveView = cell.commentResponseView {
wantToRemoveView.isHidden = false
}
}
Create a height constraint for that view and hook it as IBOutlet and control it's constant according to that in cellForRowAt
self.askViewH.constant = show ? 50 : 0
cell.layoutIfNeeded()
return cell
I expect you using automatic tableView cells
#Alexa289 One suggestion is that you can take heightConstraints of UIView. then create IBOutlet of your height constraints and make its constant 0 when you want to hide otherwise assign value to your static height.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "defectCell", for: indexPath) as! RequestDefectCell
let dataDefect = listDefects[indexPath.row]
cell.defectData = dataDefect
if dataDefect.status == 2 {
cell.viewSatisficationHeightConstraints.constant = 50
} else {
cell.viewSatisficationHeightConstraints.constant = 0
}
return cell
}
Second suggestion is that you can take label and button in view and embed stackview to your view(view contain label and button)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "defectCell", for: indexPath) as! RequestDefectCell
let dataDefect = listDefects[indexPath.row]
cell.defectData = dataDefect
if dataDefect.status == 2 {
cell.viewSatisfication.isHidden = false
} else {
cell.viewSatisfication.isHidden = true
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 40
}
you can read about UIStackView which makes hiding things easier. If you are not using stackview and hiding things the UI will not good as the space used by the hidden view will be still there. So better to use stackView when need to hide or show some view.
UIStackView : https://developer.apple.com/documentation/uikit/uistackview
I'm struggling to load a cell in cellForRowAtIndexPath in such way so that I can give a custom offset to one cell only - in my case only to Cell 1, Section 1. I'd like to give a custom offset to the cell, as the same cell (xib) is used in other parts of the project where it extends to the edges of the table without any offset. All my cells are designed as *.xib files. I'm willing to set something in awakeFromNib() or other methods, if there's the need for that.
Is there any way to set the cell offset, inset, margins, padding (not sure about the correct wording) at time of the creation or at time of loading of the cell?
I've tried to set margins in this way, but it doesn't work:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (indexPath.section == 0) && (indexPath.row) == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyCell
cell.layoutMargins = UIEdgeInsetsMake(10, 10, 10, 10)
return cell
}
} else {
// Load other cells
}
I think you're close with your cellForRowAtIndexPath implementation. Try applying the margins to the cell's contentView (the superview for your cell's content, and a subview of the cell). You may also have to set the cell's background colour to clear (the contentView will still be white).
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (indexPath.section == 0) && (indexPath.row) == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyCell
cell.contentView.layoutMargins = UIEdgeInsetsMake(10, 10, 10, 10)
return cell
}
} else {
// Load other cells
}
i'm trying to Hide a cell from a UITableView. just like the delete action do but i just want to hide it to later show it in the same position.
i know that UITableViewCell has a property called "Hidden" but when i hide the Cell using this property it hide but no animated and they leave a blank space
Example:
first cell
second cell
third cell
it's possible that when i hide the second cell, that third cell change position to 2 ?
thanks
One way to effectively "hide" a row with animation and without actually removing it is to set it's height to zero. You'd do so by overriding -tableView:heightForRowAtIndexPath:.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat height = 0.0;
if (isRowHidden) {
height = 0.0;
} else {
height = 44.0;
}
return height;
}
(You'd only want to return 0.0 for the specific row or rows you want to hide of course, not unconditionally).
Simply changing the return value of this method doesn't make the table view automatically adjust the row's height, to make it do so you make the following calls.
isRowHidden = YES;
[tableView beginUpdates];
[tableView endUpdates];
If you do so you'll see an animated appearance/disappearance transition between the two.
In SWIFT you need to do two things,
HIDE your cell. (because reusable cell may conflict)
Set Height of cell to ZERO.
Look at here,
HIDE cell
func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
if indexPath.row == 1 {
cell?.hidden = true
} else {
cell?.hidden = false
}
return cell
}
Set Height of cell to ZERO.
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
var rowHeight:CGFloat = 0.0
if(indexPath.row == 1){
rowHeight = 0.0
} else {
rowHeight = 55.0 //or whatever you like
}
return rowHeight
}
Using this you can remove reusable cell conflict issues.
You can do the same for cell?.tag also to hide specific cell by tag.
Ref: https://stackoverflow.com/a/28020367/3411787
You can't simply hide a UITableViewCell. You have to remove that cell from the table view then insert it again when you would like it to reappear in the table.
The methods you're looking for are deleteRowsAtIndexPaths:withRowAnimation: and insertRowsAtIndexPaths:withRowAnimation:. These are well documented in the UITableView documentation here. You're going to have to remember where you removed the cell from then insert it at the same position later.
Keep in mind that if you add cells to your table with a lesser row index than the row index of the deleted row, you will have to add on to the index to maintain it's relative position.
Hope this helps.
Same as Zaid Pathan but for Swift 4:
//HIDE you cell.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCell(withIdentifier: "cellID", for: indexPath) as! UITableViewCell
//hide second cell
indexPath.row == 1 ? (cell.isHidden = true): (cell.isHidden = false)
return myCell
}
//Set Height of cell to ZERO.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var rowHeight:CGFloat = 0.0
indexPath.row == 1 ? (rowHeight = 0.0): (rowHeight = 49.0)
return rowHeight
}
If you want the other cells to have a dynamic height:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 1 { // Or any other row
return 0
}
return -1.0
}
I am using Hidden in Attributes Inspector of TableViewCell -> ContentView and then implement method:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if shouldHideSection(indexPath.section) {
return 0.0
} else if let isHidden = tableView.cellForRow(at: indexPath)?.contentView.isHidden, isHidden {
return 0.0
}
return super.tableView(tableView, heightForRowAt: indexPath)
}
You should delete row and reload table view
[tbv reloadData];
cell display, depending on the data source, so you need to deal with the data source.
if dataArr is the table view datasource,first of all, you should delete the data source where the cell,then
[dataArr removeObjectAtIndex:indexpath.row];
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:#[indexpath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
at last ,you can insert data source when you should add a cell
[dataArr insertObjectAtIndex:indexpath.row];
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:#[indexpath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
Best way to set rowHeight value in condition check
Dataarray where value stored .
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//set up here
let cell = myTableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! myCustomCell
if (dataArray?[indexPath.row].somevalue == "true")
{
cell.isHidden = true
tableview.rowHeight = 0.0
}
else{
// show cell values
tableview.rowHeight = 130
}
`
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let dicttemp : Dictionary = arrAllCoursesList[indexPath.row] as! Dictionary<String,Any>
var rowHeight:CGFloat = 0.0
if let getStatus = dicttemp["status"] as? String
{
if getStatus == "1"
{
rowHeight = 240.0
}
else
{
rowHeight = 0.0
}
}
return rowHeight
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CompetitionTableViewCell") as! CompetitionTableViewCell
let dicttemp : Dictionary = arrAllCoursesList[indexPath.row] as! Dictionary<String,Any>
if let getStatus = dicttemp["status"] as? String
{
if getStatus == "1"
{
cell.isHidden = false
}
else
{
cell.isHidden = true
}
}
cell.selectionStyle = UITableViewCellSelectionStyle.none
return cell
}