I have close to 30 cells being occupied in my UITableView. I used storyboard mode to create the table. When I'm trying to call the cell that I selected its registering as 0 no matter what cell I've chosen. How do I get my cell to register the exact number I pushed and insert that into my currentTag?
Here is what I have so far
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return catNames.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = catNames[indexPath.row]
cell.textLabel?.textColor = UIColor.whiteColor()
cell.backgroundColor = UIColor(red: 0x0e/255, green: 0x1b/255, blue: 0x35/255, alpha: 1.0)
cell.textLabel?.textAlignment = NSTextAlignment.Left
cell.textLabel?.lineBreakMode = NSLineBreakMode.ByTruncatingMiddle
cell.textLabel?.adjustsFontSizeToFitWidth = true
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
currentTag = tableView.tag
println("This is the \(currentTag)")
self.performSegueWithIdentifier("table2Segue", sender:self)
}
Use indexPath.row to find out which cell it is. If you have sections you will need to use indexPath.section as well.
NSIndexPath provides the section and row for the table view selection.
Similarly to how you set the cell's text via catNames[indexPath.row], you should use indexPath.row to determine the index of the cell that was tapped.
Therefore:
currentTag = indexPath.row;
Related
I have a situation where I have to use two different prototype cells for a single tableView. These two prototype cells have different heights. When I am trying to run the application I am not getting different heights of the cell. Instead, I am getting overlapping cells. The cells are overlapped on each other at index 2.
I have made two xib for the cells and registered the two cells in tableview.
Screenshot of what I am getting
extension Redeem: UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0{
let cell1 = tableView.dequeueReusableCell(withIdentifier: "RedeemCell1", for: indexPath) as! RedeemCell1
return cell1
} else if indexPath.row == 1{
let cell1 = tableView.dequeueReusableCell(withIdentifier: "RedeemCell1", for: indexPath) as! RedeemCell1
return cell1
} else if indexPath.row == 2{
let cell2 = tableView.dequeueReusableCell(withIdentifier: "RedeemCell2", for: indexPath) as! RedeemCell2
return cell2
} else if indexPath.row == 3{
let cell1 = tableView.dequeueReusableCell(withIdentifier: "RedeemCell1", for: indexPath) as! RedeemCell1
return cell1
} else {
let cell1 = tableView.dequeueReusableCell(withIdentifier: "RedeemCell1", for: indexPath) as! RedeemCell1
return cell1
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
}
I think, the cells are not layouted correctly.
To define the cell’s height, you need an unbroken chain of constraints
and views (with defined heights) to fill the area between the content
view’s top edge and its bottom edge.
If you use XIBs in cells, you can change simulated size in cell, and see what's happened. The cell should be without broken constraints.
You need to either implement heightForRowAt
func tableView(_ tableView: UITableView,heightForRowAt indexPath: IndexPath) -> CGFloat
if indexPath.row == 0 {
return 200
}
else if {} // and so on
}
or use dynamic height table cells
So I have a mainTableView of type ExpyTableView (https://github.com/okhanokbay/ExpyTableView). All fine , i managed to implement it and make it work but as it can be seen in the gif below i need to make +1 extra action for DidSelect and DidDeselect.
The thing is i want when selected to highlight with the green color and immediately expand the other rows , and when clicked on it right after to deselect and make the row back to normal . So normally this need to happen only after 2 taps on the screen... instead i make 4 as seen in the gif.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//MARK : Print
print("Selected Section \(indexPath.section), Row : \(indexPath.row)")
///////////////
if let cell = tableView.cellForRow(at: indexPath) {
if (indexPath.section == 1) || (indexPath.section == 2) || (indexPath.section == 3) {
cell.layer.borderWidth = 2.0
cell.layer.borderColor = Theme.defaultColor().cgColor
cell.layer.shadowOffset = CGSize.init(width: 0.5, height: 0.5)
}
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
tableView.deselectRow(at: indexPath, animated: false)
cell.layer.borderWidth = 0.1
cell.layer.borderColor = UIColor.lightGray.cgColor
}
}
Where did I go wrong?
Basically you listen to table changes for didDeselectRow which means following:
The code is executed once the table view cell is deselected. So you can forget about that code unless you really need it. However what you did is that you selects the row twice. Once for expansion, secondly to collapse.
What you need to do is to remember the index of selected cell and then deselect it while id didSelectRowAt
So declare a property fileprivate var currentlySelectedCellIndexPath: IndexPath? and then in didSelectRowAt use following.
var currentlySelectedCellIndexPath: IndexPath?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let currentlySelectedCellIndexPath = currentlySelectedCellIndexPath {
// unselect the selected one
makeCellUnSelected(in: tableView, on: currentlySelectedCellIndexPath)
guard currentlySelectedCellIndexPath != indexPath else {
tableView.deselectRow(at: currentlySelectedCellIndexPath , animated: true)
self.currentlySelectedCellIndexPath = nil
return
}
}
// Highlight the proper cell
makeCellSelected(in: tableView, on: indexPath)
currentlySelectedCellIndexPath = indexPath
}
func makeCellSelected(in tableView: UITableView, on indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
if (indexPath.section == 1) || (indexPath.section == 2) || (indexPath.section == 3) {
cell.layer.borderWidth = 2.0
cell.layer.borderColor = Theme.defaultColor().cgColor
cell.layer.shadowOffset = CGSize.init(width: 0.5, height: 0.5)
}
}
}
func makeCellUnSelected(in tableView: UITableView, on indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
cell.layer.borderWidth = 0.1
cell.layer.borderColor = UIColor.lightGray.cgColor
}
}
To explain what it does:
The functions makeCellselected & makeCellUnselected just apply the style changes to highlight / unhighlight the cell as you did previously.
in the function func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) just check for currently visible and selected cell. If it is the same cell, then collapse it in guard and return, since you require only to expand / collapse. If it is not the same cell, then just discard the selection by calling makeCellUnselected and select the new one. This should solve your problem so far. If you have any other questions, just let me know.
What I would do is to have a property in your model isExpanded that will store if the cell needs to be expanded. That way you can use it in heightForRowAtIndexPath where you will get the item and read the isExpanded property.
I have a UIViewController in mainstoryboard, and it contains a tableview, it just shows the labels, not exciting things. And when I click one of the cells it push me to the detailVC. The problem is starting here, when I come back from detailVC, the cell that i pushed, is still looking selected. And it looks gross. I tried everything that i can. And lastly cells are custom cell.
P.s.: I have to use swift 2.3 in this project.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableVieww.dequeueReusableCellWithIdentifier("cellNew", forIndexPath: indexPath) as! AltKategoriNewCell
let data = self.katData[indexPath.row]
cell.textLabelNew?.text = data["CatogryName"] as? String
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableVieww.dequeueReusableCellWithIdentifier("cellNew", forIndexPath: indexPath) as! AltKategoriNewCell
let data = self.katData[indexPath.row]
cell.textLabelNew?.text = data["CatogryName"] as? String
cell.contentView.backgroundColor = UIColor.lightGrayColor()
cell.backgroundColor = UIColor.lightGrayColor()
cell.textLabelNew?.textColor = UIColor.blackColor()
urunlerList.altKatDic = self.katData[indexPath.row]
performSegueWithIdentifier("urunlerList", sender: nil)
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableVieww.dequeueReusableCellWithIdentifier("cellNew", forIndexPath: indexPath) as! AltKategoriNewCell
cell.contentView.backgroundColor = UIColor.whiteColor()
cell.backgroundColor = UIColor.whiteColor()
cell.textLabelNew?.textColor = UIColor.blackColor()
}
TableView
Attributes
First thing that is wrong is that you are dequeueing the cell in didSelectRowAtIndexPath and didDeselectRowAtIndexPath methods. UITableView does not expect you to do that there. If you need to get the cell in didSelectRowAtIndexPath, you can ask
let cell = tableView.cellForRow(at: indexPath)
UITableViewCell has selectedBackgroundView and, UILabel has highlightedTextColor. Knowing that, you can just set up appropriately your cell, and then you won't need to modify its properties on selection/deselection, like this:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cellNew", forIndexPath: indexPath) as! AltKategoriNewCell
if nil == cell.selectedBackgroundView {
cell.selectedBackgroundView = UIView()
cell.selectedBackgroundView?.backgroundColor = UIColor.lightGrayColor()
}
let data = self.katData[indexPath.row]
cell.textLabelNew?.text = data["CatogryName"] as? String
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
urunlerList.altKatDic = self.katData[indexPath.row]
performSegueWithIdentifier("urunlerList", sender: nil)
}
Having this, your implementation of didSelectRowAtIndexPath and didDeselectRowAtIndexPath can be removed.
I want to make the user multiple choice (years) or choose (all) and the rest of the cells disappear (checkmark).
I want the user can not cancel each (checkmark).
This My Code :-
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
cell?.accessoryType = .checkmark
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! yearsCell
cell.years?.text = Years[indexPath.row]
return cell }
The way I do this is by storing the selectedindexPath's in an array, then reload the tableView to change the cells that were selected, this way you avoid problems with cell re-use, this might look like this (un-tested).
var selectedIndexPathArray = Array<NSIndexPath>()
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
selectedIndexPathArray.append(indexPath)
tableView.reloadData()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! yearsCell
cell.years?.text = Years[indexPath.row]
cell.accessoryType = .none
for sip in selectedIndexPathArray {
if indexPath == sip {
cell.accessoryType = .checkmark
}
}
return cell
}
Like So:
SWIFT 3
// To checkmark the cell
let cell = tableView.cellForRow(at:indexPath.row)
cell.accessoryType = .checkmark
// To make it unselectable
Use the tableView:willSelectRowAtIndexPath: method and check if the indexPath.row is the row for the cell you just selected, and return false.
The cell is reusable. For example, the cell used to display 1st row might be used to display 10th row when scroll down. Therefore, you need a array store the checkmark status for each row, some code like:
didSelect: array[indexpath.row] = !array[indexpath.row]
cellForRow: setCheckmark(array[indexpath.row])
MORE: google how and why a cell is reused in tableview
My tableview highlights the wrong cells when I scroll up and down. In didSelectRowAtIndexPath, I'm trying to add the .Checkmark accessory view as well as change the font of cell.textLabel?.text. Upon scrolling, random rows are selected and the ones I manually select sometimes deselect.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath) as! MyCell
cell.textLabel?.text = self.array[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var cell: UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
if cell.accessoryType == UITableViewCellAccessoryType.Checkmark {
cell.accessoryType = .None
cell.textLabel!.font = UIFont(name: "HelveticaNeue", size: 16)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
} else if cell.accessoryType == UITableViewCellAccessoryType.None {
cell.accessoryType = .Checkmark
cell.textLabel!.font = UIFont(name: "HelveticaNeue-Bold", size: 16)
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
Declare array which will keep track of which rows are selected:
var selectedRows:[Bool] = []
You need to make sure that it is populated with the same number of items as your data array.
Then modify your cellForRowAtIndexPath:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath) as! MyCell
cell.textLabel?.text = self.array[indexPath.row]
if selectedRows[indexPath.row] {
// row selected
cell.accessoryType = .Checkmark
}
else {
cell.accessoryType = .None
}
return cell
}
And in your didSelectRow function add line:
selectedRows[indexPath.row] = !selectedRows[indexPath.row]
When you modify your cell from didSelectRow the next time cell is dequeued it will have the accessory type which you set. The reason why it happens after scroll is because when you scroll the cells which become visible get dequeued. So, you need to manually set correct accessory type for them