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
}
Related
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.
I Have a UITableView which is controlled by NSFetchedResultsController. I want to add single cell to the first row and make this cell static. In other words, there will be a button which will open another View Controller.
Until now, I was ok with fetched results controller and table. Now I'm a bit confused. How should I do this?
Instead using a header might be ok too, but I don't want this header to be on top all the time. I want this cell to be just like WhatsApp iOS "Create new group" cell on chats panel.
Thank you!
var dataArray = ["A","B","C"]
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.dataArray.count+1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
if indexPath.row == 0
{
let cell = tableView.dequeueReusableCell(withIdentifier: "CreateNewGroupCell") as! CreateNewGroupCell
return cell
}
else
{
// Get the data from Array
let data = self.dataArray[indexPath.row-1]
// Logic to show other cells
let cell = tableView.dequeueReusableCell(withIdentifier: "OtherCell") as! OtherCell
return cell
// ....
}
}
You will need to create tableview with number of rows fetched from NSFetchedResultsController +1. Also in cellForRowIndex method you will need to add a check like indexPath.row == 0 and in there you will make the changes.
Also you will have to add action for that button within that section. You can also set different custom tableview for first row.
It can be similar to following:
func tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: IndexPath) -> UITableViewCell {
if(indexPath.row==0){
let cell = tableView.dequeueReusableCell(withIdentifier: "CellWithButton", for: indexPath) as! CellWithButton
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: "OtherCells", for: indexPath) as! OtherCells
//here add data for cells from your array
}
return cell
}
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 implement an expanding cell using this
here is my heightForRowAt indexPath
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.row {
case 0 : return 70
case 1 :
let cell = self.tableView(tableView, cellForRowAt: indexPath)
if let datePickerCell = cell as? MyDatePickerCell {
return datePickerCell.datePickerHeight()
}
return 260
case 2 : return 80
default : return 60
}
}
The app gets stuck at
let cell = self.tableView(tableView, cellForRowAt: indexPath)
the UITableView is embeded in a modal UIViewController
why is this happening?
I think what is happening is that your tableView is looking for the heights of your cells before loading them in the first place. So you are trying to retrieve the cell before it is loaded, causing a crash.
To fix this you could create a dummy cell before loading the tableView and using that cell in heightForCell. That's more applicable for calculating variable heights for each cell though. In this case maybe hardcode the start height and then use the cell for heights after that.
So I'm setting a UITableViewCell's layout programmatically when it is selected:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.selectedCellIndexPath = indexPath
var selectedCell = tableView.cellForRowAtIndexPath(indexPath)!
tableView.beginUpdates()
tableView.endUpdates()
var cell:SelectedPatientCell = tableView.dequeueReusableCellWithIdentifier("patient selected", forIndexPath: indexPath) as! SelectedPatientCell
cell.patientName.text = patients[indexPath.row].fullName
cell.dob.text = patients[indexPath.row].dob
...
selectedCell = cell
}
And when I scroll the tableView, the layout of the cell resets to its original layout set in cellForRowAtIndexPath. However, the height stays as it should when I set it in the function above. Does anyone know how to fix this?
Here is an album of what's happening:
http://imgur.com/a/OUIMJ
Image 1:original state
Image 2: selected state (how it should stay on scrolling)
Image 3: what actually happens
you should hold this state in
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath == self.selectedCellIndexPath {
var cell:SelectedPatientCell = tableView.dequeueReusableCellWithIdentifier("patient selected", forIndexPath: indexPath) as! SelectedPatientCell
cell.patientName.text = patients[indexPath.row].fullName
cell.dob.text = patients[indexPath.row].dob
return cell
}
let cell = tableView.dequeueReusableCellWithIdentifier("patient selected") as! OriCell
...
return cell
}
in this way if you scroll tableView,it won't resume to original Cell.
Hopefully it is clear.
So I found my own solution:
Instead of doing
tableView.beginUpdates()
tableView.endUpdates()
I needed to do this at the end of the function:
tableView.reloadData()
and that solves the issue