So, I think my problem is straightforward but I can't figure out how to do it:
I have UITableView inside of UIViewController. Let's say tableView has 50 cells. So the question is how can I get instance of exactly 3'rd cell from the top (for example). For example I want just to change background color of third cel from the top.
My code look like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
cell.textLabel?.text = dataArray[indexPath.row]
if indexPath.row == 3 {
cell.backgroundColor = UIColor.init(white: 0.9, alpha: 1)
}
return cell
}
I know this code will not work because cells dequeuing.
You could change the color of the 3rd cell in different ways.
I think, in this case, you're missing the else block in order to reset the background for other cells that will dequeue the same object.
Your code is correct you just need to account for the else case.
if indexPath.row == 3 {
cell.backgroundColor = UIColor(white: 0.9, alpha: 1)
} else {
//reset your cell to default so dequeue will work correctly
}
if want to change color in cellforrowAtindexpath then:
if indexPath.row == 3 {
cell.backgroundColor = UIColor(white: 0.4, alpha: 1)
} else {
//reset your cell to default so dequeue will work correctly
}
/**************/
if out Side that function then
let Cell = tableView.cellForRow(at: IndexPath(row: 3, section: 0))
cell.backgroundColor = UIColor(white: 0.4, alpha: 1)
If you mean you want the third from the top of the screen then J=just use visibleCells
let cell = tableView.visibleCells[2]
If you mean you want the third cell in the tableView then your code is almost correct. The third cell is at row 2, because the first cell is at row 0. To trigger the change you would call tableView.reloadRows
tableView.reloadRows(at: [IndexPath(row: 2, section: 0)], with: .automatic)
Related
So the issue is when a cell is tapped, desired data is shown and when again tapped on same cell ( again desired data is shown.)
But when one cell is selected and we again select other cell (then the data is been shown of second tapped cell but the first one is not deselected).
How can I take care of this issue?
var selectedIndex = -1
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
UIView.animate(withDuration: 1) {
self.labelViewHeightConstraint.constant = 60
self.labelLeadingConstraint.constant = 136
self.view.layoutIfNeeded()
}
let cell = tableView.cellForRow(at: indexPath) as! CustomCell
if(selectedIndex == indexPath.row) {
selectedIndex = -1
print("deselect")
UIView.animate(withDuration: 0.4) {
cell.secondView.isHidden = true
cell.firstView.backgroundColor = UIColor(red: 0.8588, green: 0.84705, blue: 0.8745, alpha: 1.0)
}
} else {
cell.secondView.isHidden = false
}
self.expandTableView.beginUpdates()
//self.expandTableView.reloadRows(at: [indexPath], with: UITableViewRowAnimation.automatic )
self.expandTableView.endUpdates()
}
You can archive single selection by setting tableView property like belwo
tableView.allowsMultipleSelection = false
This can also be done from Attributes Inspector
Hope this helps
you must disable multiple selection by,
self.tbl.allowsMultipleSelection = false
and enable single selection by,
self.tbl.allowsSelection = true
EDIT:-
if you want to access your old (selected cells), you should make a call like this,
//first assign tag or indexPath in Cell,
cell.tag = indexPath.row
// or
cell.indexPath = indexPath
//then fetch like bellow,
let visibleCell = tableView.visibleCells.filter({$0.tag == self.selectedIndex})
//or
let visibleCell = tableView.visibleCells.filter({$0.indexPath.row == self.selectedIndex})
//if you use ,
let cell = tableView.cellForRow(at: indexPath) as! CustomCell
//then it will get you new cell object.
So I selected a cell in tableview.
it expands, shows detail text of the that cell then I started scrolling down till this selected cell goes out of view.
because of reuse identifier other cell in the the view get some the property of the selected cell automatically.
Is there any way to handle this ?
var selectedIndex = -1
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
UIView.animate(withDuration: 1) {
self.labelViewHeightConstraint.constant = 60
self.labelLeadingConstraint.constant = 136
self.view.layoutIfNeeded()
}
let cell = tableView.cellForRow(at: indexPath) as! CustomCell
if(selectedIndex == indexPath.row) {
selectedIndex = -1
print("deselect")
UIView.animate(withDuration: 0.4) {
cell.secondView.isHidden = true
cell.firstView.backgroundColor = UIColor(red: 0.8588, green: 0.84705, blue: 0.8745, alpha: 1.0)
}
} else {
cell.secondView.isHidden = false
}
self.expandTableView.beginUpdates()
//self.expandTableView.reloadRows(at: [indexPath], with: UITableViewRowAnimation.automatic )
self.expandTableView.endUpdates()
}
And i have deselect tableview function as
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPathaddres , animated: true)
if let cell = tableView.cellForRow(at: indexPath) as? customCell {
cell.firstView.backgroundColor = UIColor(red: 0.8588, green: 0.84705, blue: 0.8745, alpha: 1.0)
print("deselected row")
}
}
I have already disabled multiple selection.
I am attaching the 2 screenshot.
I 1 is select first cell of tableview then scroll down https://drive.google.com/file/d/1RZlya_eVVjDzj02GKV9h0qJU8F29xMin/view?usp=drivesdk once that cell goes out of scope.
Jump server 3 (as seen in this screenshot gets selected) https://drive.google.com/file/d/15k4gLUPkgB6jGZ7AWR6km0Jajst9KKxM/view?usp=drivesdk get selected
Since tableview reuses its cells, you need to do some extra checks if you want your one cell to be different from the others.
Reset the cell to its default in prepareForReuse method. Like
hiding your view and reset the arrow direction in your case.
Check for selected index in your cellForRow method and expand your view like you do in your didSelectRow method and hide it if its not selected just as you do in your didDeselect method.
What I want to ask you is "Can one UITableviewcell be used for multiple tableview like viewholder that can use anytime for recyclerview in android?" what I used to do is in one viewcontroller I have a tableview with a custom Cell and gave its identifier as normal but if I trying to use another uitableview in another Viewcontroller with that cell that inside the previous tableview, it always gives me a blank cell with white background. is there a way to use it like that?
EDIT: Here is what my tableview look like when i've already set cellforrow for it already.
Click to view and here what my cell look like Click to view cell and here are my code for different cell in a tableview, It'll work if i use use those 2 cell in current tableview
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0{
let cell = self.mytable.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! HistoryItemTableCell
let view = UIView(frame: CGRect(x: 0, y: cell.frame.maxY, width: cell.frame.size.width, height: cell.frame.size.height))
view.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.3)
cell.selectedBackgroundView = view
let order = OrderItemObj
cell.num_of_day.text = "\(order.ticket_type.name)"
cell.ref_num.text = order.order_tx_number
cell.quantity.text = order.number_tickets
cell.price.text = "$\(order.ticket_type.price).00 USD"
if order.status == "unpaid"{
cell.ic_status.image = UIImage(named: "ic_status_unpaid")
}else{
cell.ic_status.image = UIImage(named: "ic_status_paid")
}
cell.start_date.text = "\(order.start_date)"
cell.end_date.text = "\(order.expired_date)"
return cell
}else{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! OrderDetailTicketCell
let t = listTicket[indexPath.row]
cell.dob.text = t.dob
cell.gender.text = t.sex
cell.nation.text = t.nationality
let url = URL(string: t.photo)
cell.imageN.kf.setImage(with: url)
return cell
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return 3
}else{
return self.listTicket.count
}
}
override func viewDidLoad(){
super.viewDidLoad()
mytable.register(HistoryItemTableCell.self, forCellReuseIdentifier: "cell")
ViewHistoryItem()
mytable.dataSource = self
mytable.delegate = self
}
Yes you can. You have to register it again for the new tableView. It is just like how you create variables using the same type. This is also a class which can be used to create objects. Doesn't matter where you want to use it.
On the other hand if you are asking if instances of the same cell which are present in a tableView can be reused in another tableView, then the answer is no, because they have only been registered for that particular tableView.
I have UITableView that I use as a sliding menu as part of SWRevealViewController.
I want to select the last cell in UITableView and implement the following:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let customCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! IGAWindAloftMenuTableViewCell
...
let sectionsAmount = tableView.numberOfSections
let rowsAmount = tableView.numberOfRowsInSection(indexPath.section)
if (indexPath.section == sectionsAmount - 1 && indexPath.row == rowsAmount - 1)
{
customCell.backgroundColor = UIColor.yellowColor()
}
return customCell
}
When I scroll all the way down, it works -- the last cell is highlighted. However, when I scroll up and down, other cells in the middle of the table get highlighted as well.
Is there any way to prevent it?
Thank you!
You have to undo the change made in the if-branch for all other cells:
if (indexPath.section == sectionsAmount - 1 && indexPath.row == rowsAmount - 1) {
customCell.backgroundColor = UIColor.yellowColor()
} else {
customCell.backgroundColor = UIColor.whiteColor() // or whatever color
}
The reason for the undesired side effect is the reusing of cells. A cell gets created, then it gets used as the last cell, then it moves off-screen and is reused somewhere else. It still contains the changed color information but is no longer at the corresponding position.
I have a problem with refreshing my custom UITableView inside an UIViewController.
When appear the tableView has all its cell with a clear backgroundcolor.
I have a "start" button above and when I click on it I want to have all the cell in another color.
I have specified the rules in:
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if self.status == "start" {
if indexPath != self.currentIndexPath {
cell.backgroundColor = UIColor(red: 0 , green: 0, blue: 0, alpha: 0.5)
} else {
cell.backgroundColor = UIColor.clearColor()
}
} else {
cell.backgroundColor = UIColor.clearColor()
}
}
In the "start" action button, I call: self.tableView.reloadData
#IBAction func startAction(sender: AnyObject) {
self.currentIndexPath = NSIndexPath(forRow: 0, inSection: 0)
self.status = "start"
self.tableView.reloadData()
}
But it's not working very well as I must scroll to update the background color.
I tried to use the self.tableView.reloadRowsAtIndexPaths method. But the result is the same.
I always must scroll the tableView to update the background color or some images.
Where am I wrong ?
Replace your call to reloadData with:
DispatchQueue.main.async { self.tableView.reloadData() }
You should probably put your logic inside the cellForRowAtIndexPath delegate method, this will get called when you reload the table.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath:indexPath)
if self.status == "start" {
if indexPath != self.currentIndexPath {
cell.backgroundColor = UIColor(red: 0 , green: 0, blue: 0, alpha: 0.5)
} else {
cell.backgroundColor = UIColor.clearColor()
}
} else {
cell.backgroundColor = UIColor.clearColor()
}
return cell
}
As I can't see your current implementation of this method I have just guessed at your dequeuing of the cell, you may need to change this slightly, If you can post this code in your question I can help.
You've got the logic in the wrong place. willDisplayCell is called just before the cell is drawn which is why it makes sense that you're seeing the change when you scroll. Calling reloadData is going to call cellForRowAtIndexPath so you should move your logic to that method.
Instead of adding your codes on WillDisplayCell add in cellForRowAtIndexPath
#IBAction func startAction(sender: UIButton)
{
let buttonPosition : CGPoint = sender.convertPoint(CGPointZero, toView: self.tableview )
self.currentIndexPath = self.tableview.indexPathForRowAtPoint(buttonPosition)!
self.status = "start"
self.tableView.reloadData()
}