I'm moving and app I had on Parse to Firebase and I ran into an issue with a cell that needs to get resized.It contains a textview that recieves data, since the text varies in size, I am using this two methods:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
With Parse this worked perfectly because I would recieve the entire object that I had to pass to the DetailTableView in the MainTableView. With Firebase, I handle it differently, I retrieve what the MainTableView needs, then I just pass a reference to the DetailTableView and again retrieve whatever I need there. The problem seems to be that the size of the cell gets set before the async function can set the text. Any ideas on how to solve this?
Thanks in advance!
I think you can wrap the code setting the text on the cell with calls to tableView.beginUpdates()
tableView.endUpdates()
Related
I have implemented two custom cells in the tableview.Now I want to replace these two custom cells with one another. How to achieve this?
Implement following tableview methods and write your code in it
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
// return boolean value for a specific or all cells, you want to enable movement
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
// Handle array element movement along with your row/cell
}
Share your full source code better help
If you would like to reorder rows in UITableView. Take a look at two delegates that are implemented in the UITableView.
They are: tableView:canMoveRowAtIndexPath: and moveRowAtIndexPath:toIndexPath:.
Also take a look at tutorial that show how it is possible to implement.
Along with tableview delegates, use moveRow(at: <IndexPath>, to: <IndexPath>), to move your row programatically (automatically), without user interaction.
tblTabel.moveRow(at: <IndexPath>, to: <IndexPath>)
// Tableview Delegates
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
// return boolean value for a specific or all cells, you want to enable movement
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
// Handle array element movement along with your row/cell
}
I'm starting to work with UITableViews and can't seem to find out how to change the position of a cell with code. Changing the position in the storyboard is straightforward enough but I need to be able to do it in swift.
TLDR;
Update your data. i.e. swap(&arr[2], &arr[3]).
Call the tableView's reloadData() method to reflect the changes to your data.
Long answer
An instance of UITableView works by checking its data source (UITableViewDataSource) for the information it needs. This includes the number of sections and rows, as well as the instance of UITableViewCell that the table view is to use. These are defined by the following UITableViewDataSource delegate methods:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int;
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int;
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell;
Usually, you would base the former two on some data you have, likely an Array or similar container. For example, if your tableView displayed data from an Array named fruitArray (which contained names of different fruit - a list of strings), then you might have something like the following:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// Our array is one dimensional, so only need one section.
// If you have an array of arrays for example, you could set this using the number of elements of your child arrays
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Number of fruits in our array
return fruitArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("yourCellId") // Set this in Interface Builder
cell.textLabel?.text = fruitArray[indexPath.row]
return cell
}
Then, you can see that the answer to your question becomes simple! Since the contents of a given cell are based upon fruitArray, all you need to do is update your array. But how do you get the tableView to "recheck" its dataSource? Well, you use the reloadData method, like so:
swap(&fruitArray[2], &fruitArray[3])
tableView.reloadData()
This then triggers the tableView to "recheck" its dataSource, hence causing your data swap to appear on the screen!
If you'd like the user to be able to swap the positions of the cells, you can use the following UITableViewDelegate (not UITableViewDataSource) delegate method:
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool
Have a look at this article for more info. You can also view Apple's documentation on UITableView, UITableViewDataSource, and UITableViewDelegate for further detail.
Hope this helps!
func tableView(tableView: UITableView, numberOfRowsInSection section: Int)
is getting called and returning non zero value.
but the following code isn't getting called.. why?
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
tableView is initially 0 size, and supposed to grow dynamically, would it be the cause of this?
cellForRowAtIndexPath will not be called if tableView's size is zero!
And you must not keep any logical part in that method. You must use that method only for updating the ui, no more.
I'm trying to call cellForRowAtIndexPath from within heightForRowAtIndexPath in order to assign a height based on the cell's type (I'm subclassing UITableViewCell). Trivial, right? Well, calling it there causes a loop. I can't quite seem to figure out why that would be. Placing breakpoints in both methods doesn't yield anything—the delegate method cellForRowAtIndexPath never actually gets called. Take a look:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
switch indexPath.row {
case 0:
return SubclassCellTypeOne()
default:
return SubclassCellTypeTwo()
}
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
// Calling cellForRowAtIndexPath here causes a loop
let cell = tableView.cellForRowAtIndexPath(indexPath)!
if cell is SubclassCellTypeOne {
return UITableViewAutomaticDimension
} else {
return 100
}
}
Any idea why that's happening? And any suggestions on how to get around it? Thanks!
When a reference to a cell is made via a UITableView, (usually by iOS, when loading your view), iOS calls the methods in its lifecycle - e.g., heightForRowAtIndexPath, editingStyleForRowAtIndexPath to work out how to display it etc.
So your source of an infinite loop is that you make a reference to a cell, inside a method that is called when a reference to a cell is made ;)
To fix this, you should reference back to your data source, instead of asking the cell directly about itself. If you have a class set up as a data collection, this is easy.
Yep, you shouldn't call cellForRow inside heightForRow.
In heightForRow you have the indexPath variable. You can use indexPath.row to determine the class of the cell inside heightForRow, just like you do in cellForRow.
You could also have forgotten to set the delegate and datasource properties of the tableview. Or you are returning 0 from numberOfRowsInTable...
That could also be why you are not hitting the breakpoint inside cellForRow.
I'm having an extremely difficult time resizing the .rowHeight of the cells in my .toDoListTable. The strings received from a UITextfield are being cut-off at the end of each row. I did not add a label when setting up a prototype cell since my strings are appended from a UITextField. My code is as follows:
override func viewDidLoad() {
super.viewDidLoad()
toDoListTable.estimatedRowHeight = 45.0
toDoListTable.rowHeight = UITableViewAutomaticDimension
}
}
Yet, I am still getting my text cut-off. Any suggestions? Also, is my code in the right spot?
I'm looking to have my content inside adapt to the amount of text provided from the UITextField.
EDIT: Solved problem by adding cell.textLabel?.numberOfLines = 0.
Use this to set the height for the rows:
override func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat
{
return 50 //your height
}
Documentation:
https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UITableViewDelegate_Protocol/index.html
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat{
return 30 // height you want to set.
}
I know I'm late but I wanted to correctly answer my own question.
I simply added: cell.textLabel?.numberOfLines = 0 to the cellForRowAtIndexPath function to allow for multiple lines of unrestricted text.