I'm trying to do something I would expect to be simplistic, but it's escaping me. I'm trying to show\hide the LAST cell in a tableview section. If I create an IBOutlet for the cell, and set it to hidden, the separator doesn't completely cover the bottom of the section. I've attached before and after examples. Any help would be appreciated.
The way I've done it with a static table is returned height 0 for the row you want to hide. In my case I made a set of index paths, then implemented it like this:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
guard hiddenIndexPaths.contains(indexPath as IndexPath) else {
return super.tableView(tableView, heightForRowAt: indexPath)
}
return 0
}
Where hiddenIndexPaths: Set<IndexPath>, is a property on your table view controller that you manage in code. Since it's a static table you should know the index path of the row you want to hide. If you have an outlet already, you can also check that the cell at that index path is the one for your outlet and return height 0 that way. But personally I find the index path set easier.
You also need to make sure that the cell has "clips to bounds" enabled in interface builder.
I think the only way you do it is set the tableview to be Dynamic Prototypes (in IB) .
Every time you try to hide/show a cell, you should callself.tableView.reloadData()
.
Then implement
var hide = false
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if( section == 1 ){
return 3 + ( hide ? 0 : 1 )
}
else {
return 1
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = self.tableView.dequeueReusableCellWithIdentifier(...) as ...
cell.<textField>.text = ...
return cell
}
Related
So every time I scroll my tableView it reloads data which I find ridiculous since it makes no sense to reload data as it hasn't been changed.
So I setup my tableView as follows:
func numberOfSections(in tableView: UITableView) -> Int {
return self.numberOfElements
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 6
}
My cells are really custom and they require spacing between them. I couldn't add an extra View to my cell to fake that spacing because I have corner radius and it just ruins it. So I had to make each row = a section and set the spacing as a section height.
My cell has a dynamic height and can change it's height when I click "more" button, so the cell extends a little.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if self.segmentedControl.selectedSegmentIndex == 0 {
if self.isCellSelectedAt[indexPath.section] {
return self.fullCellHeight
} else {
return self.shortCellHeight
}
} else {
return 148
}
}
And here's how I setup my cell:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = UITableViewCell()
if self.segmentedControl.selectedSegmentIndex == 0 {
cell = tableView.dequeueReusableCell(withIdentifier: String.className(CurrentDocCell.self)) as! CurrentDocCell
(cell as! CurrentDocCell).delegate = self
(cell as! CurrentDocCell).ID = indexPath.section
} else {
cell = tableView.dequeueReusableCell(withIdentifier: String.className(PromissoryDocCell.self)) as! PromissoryDocCell
}
return cell
}
So I have a segmentedControl by switching which I can present either one cell of a certain height or the other one which is expandable.
In my viewDidLoad I have only these settings for tableView:
self.tableView.registerCellNib(CurrentDocCell.self)
self.tableView.registerCellNib(PromissoryDocCell.self)
And to expand the cell I have this delegate method:
func showDetails(at ID: Int) {
self.tableView.beginUpdates()
self.isCellSelectedAt[ID] = !self.isCellSelectedAt[ID]
self.tableView.endUpdates()
}
I set a breakpoint at cellForRowAt tableView method and it indeed gets called every time I scroll my tableView.
Any ideas? I feel like doing another approach to make cell spacing might fix this issue.
A UITableView only loads that part of its datasource which gets currently displayed. This dramatically increases the performance of the tableview, especially if the datasource contains thousands of records.
So it is the normal behaviour to reload the needed parts of the datasource when you scroll.
After much searching and reading I unfortunately do not come from the following. I want to use static tables to display certain data. (Are there better options?)
In my view I first put an onion picture with a container view underneath. The container view again refers to a Table View Controller.
I made an outlet from the cells and then I thought I could easily adjust the text.
Now I want to change the text of the fields in the table, but unfortunately I do not succeed.
When I start the app then the table is completely empty as seen on the screenshot.
What am I doing wrong ?
class TableViewController: UITableViewController {
var data: [String] = ["Muis", "Aap", "Koe", "Vis"]
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let iets = data[indexPath.row]
cell.textLabel?.text = iets
return cell
}
}
If you want to use static cells
Forget dequeueing UITableViewCell instances and all tableview data source and delegate methods.
In Interface Builder select the table view and select Static Cells from the Content popup
Drag the amount of static cells you need into the canvas
In the view controller declare IBOutlets and connect them directly to the UI elements in the cells
You need to change your way of thinking for this one. You do not own the cells, the UITableView does. It will provide cells as it seems fit by using your implementations of UITableViewDataSource:
func numberOfSections(in: UITableView) -> Int
func tableView(UITableView, numberOfRowsInSection: Int) -> Int
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell
Normally, the texts (your actual data) would be held in a list available to this data source.
Example:
var data: [String] = []
// Other functions
func numberOfSections(in: UITableView) -> Int {
return 1
}
func tableView(UITableView, numberOfRowsInSection: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "YOUR_IDENTIFIER")
cell.text = data[indexPath.row]
return cell
}
Now, if you want to change this cell's text, all you have to do is update your data list and reload the data.
What I have done after a lot of testing and reading. I have create a segue to the statutable class.
if (segue.identifier == "myEmbeddedSegue") {
let childViewController = segue.destination as! hondDetialTableViewController
childViewController.hondId = hondData["hondId"]!
}
In this segue I send only the hondId, everything else i ask entities.
I'm sorry but this is not at all how UITableView works. The UITableViewCell that you define in the Xib/Storyboard within the tableview are just "models" or templates, they don't actually exists until you dequeue them.
You can read how UITableView works here: http://www.thomashanning.com/uitableview-tutorial-for-beginners/
You have to return numberOfSections > 0 if you want anything displayed in your tableview; similarly, that section has to also have numberOfRows > 0 otherwise again, nothing will be displayed (ok, maybe headers and footers if those are properly setup).
At any rate, cells are only accessible after you dequeue them. Creating an outlet in a XIB to a UITableViewCell is useless in most cases.
You can explore other options, such as UIStackView, or maybe what you need is just plain custom UIView with labels that you properly set and layout using NSLayoutConstraints. There are plenty of resources out there, this is just one I quickly Googled for you to get started: https://www.youtube.com/watch?v=de0sthle44I
Good Luck.
I have a UITableViewController. In the code of the tableview I want to display a "lineLabel" (which is just a blank label with a background at the bottom of the cell), if a value is equal to another value - and I got that working pretty nice!
The problem is that when I reach the bottom cell I get the index out of range error. I know why I get the error (will show you in code), but I do not know how to prevent that error and still get the same result as I do now?
Hope you can help me!
Here is my code:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:carTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! carTableViewCell
let checkBackgroundColor = carsArray[indexPath.row + 1].componentsSeparatedByString("#")
if checkBackgroundColor[4] == finalCars[4] {
cell.lineLabel.hidden = true
} else {
cell.lineLabel.hidden = false
}
return cell
}
I get the index out of range error, because I am checking for an index that isn't there, in the workoutsArray[indexPath.row + 1].componentsSeparatedByString("#") part of my code. I just do not know how to do this otherwise? Anyone??
Check an array count before:
if carsArray.count > indexPath.row + 1 {
// your code here
}
but also you MUST do the proper calculations of your tableview rows count and put it inside your override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
I have a tableview inside my UIViewController to display comments. The height of this tableview depends on the number and the size of comments. The cells are dynamic.
I use autolayout, so my tableview has a height constraint. I set this constraint programmatically :
override func viewDidLayoutSubviews() {
self.heightCommentsTableView.constant = self.commentsTableView.contentSize.height + 50
}
It works if I display all the comments at once.
BUT, I would like display the comments 5 per 5, using this method : load more for UITableView in swift because of performance issue to display my view
(all my comments are loaded before pushing the view)
I noticed when I set my constraint, it calls cellForRowAtIndexPath for all the comments, not only the first 5.
I don't know how to do.
EDIT
var allCommentsArray: NSMutableArray = []
var elements: NSMutableArray = []
var range = 5
var currentPage = 0
var nextpage = 0
override func viewDidLoad() {
super.viewDidLoad()
allCommentsArray = NSMutableArray(array: comments)
elements.addObjectsFromArray(allCommentsArray.subarrayWithRange(NSMakeRange(0, range)))
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return comments.count
}
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
self.nextpage = self.elements.count - 5
if indexPath.row == nextpage {
self.currentPage++
self.nextpage = self.elements.count - 5
self.elements.addObjectsFromArray(self.allCommentsArray.subarrayWithRange(NSMakeRange(self.currentPage, self.range)))
tableView.reloadData()
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CommentCustomTableViewCell", forIndexPath: indexPath) as! CommentCustomTableViewCell
self.configureCell(cell, atIndexPath: indexPath)
return cell
}
The table view will call tableView(_:cellForRowAtIndexPath:) for every visible cell it is about to create, the amount of it will determine based on how many sections and how many cells in each section. You let the table vie know these amounts by implementing the tableView(_:numberOfRowsInSection:) and numberOfSectionsInTableView(_:) methods of UITableViewDataSource. So, if you want to control how many cells could possibly be created and visible at a given time, you'd have to manage that state in your data source by adding and removing according to whatever logic you desire. In the answer that you linked, you can see that he is called elements.addObjectsFromArray to progressively add more elements in batches.
I have a table that loads data from a database but the problem is if the text being loaded is too long, it goes off the screen. I'm trying to find a way for the text to go onto the next line and have the cell resize automatically to fit this change. Does anyone know how this is done? The cell has three labels but one of them is allowed to be multi-lined.
EDIT:
I got it to work using auto constraints but how can I resize the table cell so that the actual items fit inside the cell and do not go over the cell boundary?
Set label number of "Lines" to ZERO. And set "Line Breaks" to "Word Wrap"
Adding these two methods along with above code fixed the problem with custom font
tamilRow.textLabel?.numberOfLines=0
tamilRow.textLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
func tableView(tableView: UITableView, heightForRowAtIndexPath
indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
swift 5
let unselectedCellHeight: CGFloat = 130.0
func tableView(_: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if selectedCellIndexPath == indexPath {
//return selectedCellHeight
return UITableView.automaticDimension
}
return unselectedCellHeight
}