TableView cell selection issue - ios

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.

Related

TableView didSelect row Issue

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.

Can the same UITableviewcell be used in multiple UITableViews?

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.

didSelectRowAt indexPath is not being called

I created a UIViewController that contains two View (Top , Bottom),
the Bottom view expands all the way to the top when clicking on the searchBar. (bottomView height expands, topView height is getting smaller).
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
self.expandBottomView()
return true
}
func expandBottomView() {
let heightToAdd = TopView.frame.height - numOfRequestsTitle.frame.height
RecomandFriendHeight.constant += heightToAdd
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded()
}
topTableView.isUserInteractionEnabled = false
}
Both View contain TableViews (topTableView , BottomTableView) all delegates are set I checked.
BottomView Contains another button to collapse the bottomView when needed.
topTableViewCell contains two Buttons and two labels.
bottomTableViewCell contains a label and an imageView.
The Problem is none of the tableViews cells invokes didSelectRowAt.
If you add button to a cell didSelectAt not called on tapping the button. In this case you have to add a selector to this button inside cellForRowAt:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! customcell
cell.btn.addTarget(self, action: #selector(clickedCell), for: .touchUpInside)
return cell
}
and implement this selector method
func clickedCell(_ sender : UIButton) {
print("clicked")
}
Make
topTableView.isUserInteractionEnabled = true

get instance of specific row in uitableview

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)

Refresh UITableView in Swift

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()
}

Resources