Swift: Add UITableViewCellAccessoryDisclosureIndicator and link to another tableview - ios

I have two tables in a tableview in one UIViewController(Not UITableViewController). Now I want to let only one of the cells adding UITableViewCellAccessoryDisclosureIndicator to let users click for viewing another tableview.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = UITableViewCell()
if indexPath.section == 0{
cell.textLabel?.text = "\(rentTitle[indexPath.row]): \(rentArray[indexPath.row])"
}else{
cell.textLabel?.text = "\(cashflowTitle[indexPath.row]): \(cashflowArray[indexPath.row])"
}
return cell
}
There are 6 rows in the first table and 5 rows in the second one. I want to add the disclosureIndicator in the third row of the second table. So the questions are: 1. How to add the disclosureIndicator in the 3rd row of the second table? 2. How to make that row actively link to another tableView? Thanks a lot!
func tableView(tableView: UITableView,accessoryButtonTappedForRowWithIndexPath indexPath: NSIndexPath){
var cell = UITableViewCell()
if indexPath.section == 1{
if indexPath.row == 2{
print(indexPath.row)
}
}
}
I tried the print first.

That arrow isn't a UINavigationItem; it's a UITableViewCellAccessoryDisclosureIndicator.
To add that UITableViewCellAccessoryDisclosureIndicator "arrow" to your cell's accessory view, add this line:
if indexPath.row == 2 { //Third row
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
}
And then to perform a specific action when that accessory view is tapped, implement
tableView:accessoryButtonTappedForRowWithIndexPath:
In this method implement your navigation by checking the indexPath again.

Related

Prevent selected cell from being reused

So I have a tableview that has a list of items in each cell. Each of these cells contain an image view which, upon being tapped, expands the cell and displays the image for that item. When I scroll down the table view and scroll back up to the cell that was selected, the image is gone. I know this is due to reusing cells but I'm not sure on how to keep the expanded cells image in place while scrolling through other items.
The closest I've come is here:
my table view reuse the selected cells when scroll -- in SWIFT
If someone could lend me a hand that would be awesome. Thanks!
Edit: Adding code snippets - Sorry for the wait.
fileprivate var expandedRowIndex: Int?
// cellForRowAt
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
// CatalogItem row.
let item = self.items[indexPath.row]
let expanded = indexPath.row == self.expandedItemRowIndex
// Return standard catalog item cell.
let reuseID = expanded
? CatalogItemCell.PROTOCELL_EXPANDED.id
: CatalogItemCell.PROTOCELL.id
let cell = tableView.dequeueReusableCell(withIdentifier: reuseID) as! CatalogItemCell
// Reset thumbnail image back to nil. Needed so that images appear
// only in the cell that they belong in.
if indexPath.row == self.expandedRowIndex{
cell.uiImage_Thumbnail.image = nil
}
return cell
}
// didSelectRowAt
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
tableView.deselectRow(at: indexPath as IndexPath, animated: true)
// Expand row - Get the current cell and show image
self.expandedItemRowIndex = indexPath.row
let item = self.items[indexPath.row]
let currentCell = tableView.cellForRow(at: indexPath)
// Pass both the selected cell and item to the ImageManager
ImageManager.startImageRequest(currentCell: currentCell!, item: item)
if self.expandedRowIndex == indexPath.row
{
// Selected row is already expanded.
return
}
var reloadPaths = [IndexPath]()
// Collapse previously expanded row.
if let previousRowIndex = self.expandedRowIndex
{
reloadPaths.append(IndexPath(row: previousRowIndex, section: 0))
}
// Expand the selected row.
self.expandedRowIndex = indexPath.row
let item = self.items[indexPath.row]
debugPrint(item.description)
reloadPaths.append(IndexPath(row: indexPath.row, section: 0))
tableView.reloadRows(at: reloadPaths as [IndexPath], with: .fade)
}
You can maintain a selectedIndex variable.
In your cellForRow you check whether this call is for selectedCell. If yes, then do the customisation that is required for selected cell.
Also you might want to handle heightForRow, there also check whether the call is for selected cell.
You can maintain an indexPath for selected cell. If there are multiple sections.
No need to prevent it from getting reused.
Hope that helps.

How to hide specific cells in a static UItableview, in swift?

No article explains it clearly regarding my query, I have three cells in a static table and I want to hide second cell when users taps on first cell. Any kind of help is appreciated.
Although you cannot stop the static table from trying to show your cells, you can set their height to zero, making them effectively invisible:
Add this method to your table view controller delegate class:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath)
return cell == myHiddenCell ? 0 : super.tableView(tableView, heightForRowAtIndexPath:indexPath)
}
In the didSelectCellAtIndexPath method, you can set the height to 0 to hide it :
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0 {
let indexPath = NSIndexPath(forItem: 1, inSection : 0)
let secondCell = tableview.cellForRowAtIndexPath(indexPath)
secondCell.frame.size.height = 0;
self.view.layoutSubviews()
}
}
If you want an animation, just put self.view.layoutSubviews() in an UIView animation method UIView.animateWithDuration... etc
For me, setting the height to 0 for some cells and another height for other cells wasn't an option, as all my cells have different height.
I created another cell in Storyboard, and set row height of 0 (in size inspector). Then in the code, I show the cell with height = 0 if I want to hide it, if not, I show the other cell:
if (hideCell) {
let hiddenCell = tableView.dequeueReusableCell(withIdentifier: "hiddenCell",for: indexPath) as! TheWallTableViewCell
return hiddenCell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell",for: indexPath) as! TheWallTableViewCell
return cell
}

Why is there a possibility that UITableViewCells can be nil within a row?

I'm currently learning the inner-workings of UITableView through a Ray Wunderlich book and noticed that in this protocal's function body it uses optional binding to create a cell.
override func tableView(tableView: UITableView , didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
if cell.accessoryType == .None {
cell. accessoryType = .Checkmark
} else {
cell.accessoryType = .None
}
}
tableView. deselectRowAtIndexPath (indexPath, animated: true )
}
The concept of optional binding is still fairly new to me so thinking aloud I'm assuming that there's the possibility that there won't be a cell in every row (i.e. returns nil)
Here's where I'm getting stuck. In my storyboard I have a table view controller and one prototype cell. Shouldn't the fact that I have this one prototype cell in the table view ensure that there will be created for however many rows are created?
The func cellForRowAtIndexPath(_ indexPath: NSIndexPath) -> UITableViewCell? method of UITableView is defined to return an optional, which is why you have to first unwrap it.
According to the docs: An object representing a cell of the table, or nil if the cell is not visible or indexPath is out of range.

Static tableView cells not showing checkmark if out of view when view loads

I have a tableview controller that I am using as a preferences screen. It has three sections, each with static cells.
The third section has 6 rows and each row represents a different date format, but depending on the device, not all appear when the view loads.
I am using the checkmark accessoryType to denote whether or not the particular option has been selected. (I get that from my Realm database store)
In the tableview in IB, I set all cells to have accessoryType - .None so initially, no checkmarks.
When the view appears, I retrieve the stored value and set the appropriate checkmark like this.
for (index,selDateFormat) in dateFormats.enumerate() {
if selDateFormat == dateFormat {
tableView.cellForRowAtIndexPath(NSIndexPath(forRow: index, inSection: 2))?.accessoryType = .Checkmark
} else {
tableView.cellForRowAtIndexPath(NSIndexPath(forRow: index, inSection: 2))?.accessoryType = .None
}
}
It works great if the row is in view so on an iPhone 6 plus, I am great. However, on an iPhone 4s, only the first two rows are shown in this section until I scroll. The problem is that if I selected an option in rows 3 - 6, the checkmark is not displayed because it was out of view when the view appeared.
Is there a way that I can get the checkmark to show when the view appears?
For those rows which are off screen, cellForRowAtIndexPath will return nil. You need to set the checkmark (or not) when the cells are created as the rows are scrolled on screen. Override cellForRowAtIndexPath and set the checkmark as required:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath)
if let selDateRow = dateFormats.indexOf(selDateFormat) {
if (indexPath.row == selDateRow) {
cell.accessoryType = .Checkmark
} else {
cell.accessoryType = .None
}
} else { // just in case selDateFormat isn't in the dateFormats array...
cell.accessoryType = .None
}
return cell
}
Turns out the answer was even simpler in code
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = super.tableView(tableView, cellForRowAtIndexPath: indexPath)
let section = indexPath.section
if section == 2 {
if dateFormats[indexPath.row] == dateFormat {
cell.accessoryType = .Checkmark
} else {
cell.accessoryType = .None
}
}
return cell
}

Perform segue when cell with ID is selected

I am trying to create a segue happen when a cell has been selected. I have tired using cell.dequeueReusableCellWithIdentifier(""). However it is returning "nil" whilst unwrapping. I have set up the cells ID correctly and they match. Any help is greatly appreciated!!
if menuTableView.dequeueReusableCellWithIdentifier("") == "logout" {
print("logout")
performSegueWithIdentifier("logoutSegue", sender: self)
}
Thanks in advance
There is a UITableView delegate method for when a user selects a cell, this is good for knowing when a user has selected a cell, but we need to identify if it is the logout cell that has been pressed.
To identify the cell we'll be setting the tag property of the your logout cell.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 {
//this is the indexPath row where we want our login cell to be showed
let loginCell = tableView.dequeueReusableCellWithIdentifier("login", forIndexPath: indexPath) as! LoginTableViewCell
//set the tag so when we select the cell we can see if the cell we have selected has a tag of 5
loginCell.tag = 5
return loginCell
}else {
//here goes our other cells, in this case they'll just be normal UITableViewCell
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
return cell
}
}
In our cellForRowAtIndexPath delegate method we'll instantiate the loginTableViewCell in the first row and set its tag to 5, if the row isn't 0 we simply return our normal cell
So now we have a cell where the tag is 5 and all the other cells do not have a default tag property of 0, now, when the user selects a cell we can check for this method in the didSelectRowAtIndexPath delegate method of our table view.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)!
if cell.tag == 5 {
//cell is login cell
//perform segue here
}
}
This delegate method gives us the table view and the indexPath of the selected cell. Now we call CellForRowAtIndexPath on the table view to get the cell that was selected. Now that we have the cell we can compare the cell's tag. If the tag is 5 the logout cell was selected so we can perform our segue there.

Resources