Adding index list and section headers to translated tableview - swift

How to add section headers and index list to UITableView in this use case?
#IBOutlet var tableView: UITableView!
var detail: Detail? = nil
var list = [tabledata]()
let search = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
list = [
tabledata(name:"something".localized, sort:"sort.something".localized, id:"something.html"),
tabledata(name:"somethingelse".localized, sort:"sort.somethingelse".localized, id:"somethingelse.html"),
...
]
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "library", for: indexPath)
var data: tabledata
data = list[indexPath.row]
cell.textLabel!.text = data.name
return cell
}
Now the point is that table data are going to be translated.
Like if the user has set the language to English, sorting is unneeded;but if the language is set to German etc., section headers have to be applied to translated table.
Can someone figure out how to call a section letter from inside the dictionary, like
tabledata(section: "a", name:"anaconda".localized, sort:"sort.anaconda".localized, id:"anaconda.html")
Note that
name: is the actual cell name going to be .localized
sort: has to help characters like á é etc. in cell name to sort properly (avoiding them to show in the end of alphabet)
id: calls the html file location to display in detailViewController ('cause name has to be translated and we want a static text here)
A usual implementation of section headers and index list will result in something like
T // section header
translation // cell names
transmission
...
T // table in
Übersetzung // another language
Getriebe
...
Maybe there could be a function() which will get all the sections from tabledata and assign them to corresponding letters in var sectionletters = ["A", "B", ...] but that's above my beginner-limited knowledge.
What's the correct model for translated tableview?
Thanks for help!

There are a few ways to accomplish this. One of the simplest is to use the delegate functions provided with UITableView.
For organizational purposes I'd start by creating a class to represent sections. Something like this:
class GhostSection {
// a title for this section
var sectionTitle: String
// a list of items for this particular section
var items: [Ghost] = []
init(title: String, items: [Ghost]) {
sectionTitle = title
self.items = items
}
}
Then update the list variable to use the sections instead of a raw list of items:
var tabledata = [GhostSections]()
Ideally I'd create my GhostSection from a json object, but if it must be done manually then something like this would work:
// setup the table data to use GhostSection instances for each section
var tabledata = [
GhostSection(title: "a", items: [Ghost(name:"an".localized, sort:"sort.an".localized, id:"0101")]),
GhostSection(title: "b", items: [Ghost(name:"bc".localized, sort:"sort.bc".localized, id:"0102")]),
GhostSection(title: "c", items: [Ghost(name:"cd".localized, sort:"sort.cd".localized, id:"0103")])
]
I'd have numberOfSections(in tableView: UITableView) return the tabledata count, which would be the count of the total number of sections:
func numberOfSections(in tableView: UITableView) -> Int {
return tabledata.count
}
and the numberOfRowsInSection return the list count for each items array on each GhostSection in your tabledata array:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tabledata[section].items.count
}
Then I'd update cellForRow(at indexPath) to return the info for the right cell in that section:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "library", for: indexPath)
// this gets the section data, then gets the item from that section
var data = list[indexPath.section].items[indexPath.row]
cell.textLabel?.text = data.name
return cell
}
I also like to create my headers as reusable nib views, so the ListHeaderView just has a title label in it:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
// this loads the view from the nib
guard let view = ListHeaderView.fromNib() as? ListHeaderView else {
return nil
}
// get the section object for this current section
let data = tabledata[section]
// and set the title label text here from our section object
view.titleLabel.text = data.sectionTitle
return view
}
// if you want to also have a custom footer you can do that here...
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
return UIView()
}
// and let the header height be dynamic, or return a set height here...
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return UITableViewAutomaticDimension
}
In case you want to use this approach here's how I implemented the fromNib() function so you can instantiate any view that has an associated .xib file:
public extension UIView {
public static func fromNib() -> UIView? {
let nibName = String(describing: self)
let bundle = Bundle(for: self)
let nib = UINib(nibName: nibName, bundle: bundle)
guard let view = nib.instantiate(withOwner: nil, options: nil).first as? UIView else {
print("Unable to instantiate nib named: \(nibName) in bundle: \(String(describing: bundle)) -- nib: \(String(describing: nib))")
return nil
}
return view
}
}
Also note it's a good idea to get in the habit of using camel case for class/object names with the first letter capitalized IF you want to keep with current conventions. So instead of naming your class ghost get in the habit of doing Ghost. For variables the convention is also camel case but start with a lowercase.

The easiest way is to use sections: one section for each first letter.
First, update your tableView(_:cellForRowAt:) to deal with sections: the first word in a section corresponds to the row value 0.
The section number corresponds to the letter: 0 for A, 1 for B, ...
In your code, you get an old cell correctly, but the way you set the text must be changed. You are doing something like that: cell.textLabel?.text = list[indexPath.row]. But this will not work because with sections, the indexPath.row parameter value is no longer the index of the ghost in your list: your list is a 1-dimension array, but with sections, UIKit uses a two dimensional way to give you the reference to the ghost: the arguments indexPath.row is now the index number of the ghost in the section indexPath.section. So if you have 4 ghost names, in your list, for instance "axx" (section 0, row 0), "ayy" (section 0, row 1), "bxx" (section 1, row 0) and "byy" (section 1, row 1), the values of the arguments to refer to "bxx", for instance, are 1 for indexPath.section and 0 for indexPath.row. With your current line of code, you will set the following text: list[0], so "axx". But it's "bxx" that corresponds to section 1 and row 0.
To get the correct behavior, you may process the whole list of ghosts, extract the ones that correspond to the letter for indexPath.section into another array, and finally get the element of this new array that has an index that equals to indexPath.row.
But as you see, this is a bit more tricky than we would like.
The best way to do all of that, easily, is to change your data source type: use a 2-dimensional array instead of your list that is of type [ghost].
You could for instance use something like:
var myNewDataSource : [String: [ghost]] = [
"A": [ghost1withNameStartingWithA, ghost2withNameStartingWithA, ...],
"B": [ghost1withNameStartingWithB, ghost2withNameStartingWithB, ...],
...
]
This way, everything is simpler.
Now, override this function, to have 26 letters or sections (you may customize this function if you want to display only letters containing at least one word):
override func numberOfSections(in tableView: UITableView) -> Int {
return 26
}
Override and implement correctly this function, to indicate how many words there are in a section, in your dictionary:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
[ COMPUTE THE NUMBER OF ROWS/WORDS FOR THIS LETTER AND RETURN THE VALUE ]
}
Then return a String with the letter for each section, in order to display this letter in the GUI:
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
[ RETURN THE LETTER CORRESPONDING TO THE SECTION: "A" for section 0, "B" for section 1, etc. ]
}
Finally, customize your sections, since you seems to want a specific background color and maybe a bold font or another font size, according to your screenshot:
override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
let header = view as! UITableViewHeaderFooterView
header.backgroundView?.backgroundColor = UIColor(red: 253.0/255.0, green: 240.0/255.0, blue: 196.0/255.0, alpha: 1)
header.textLabel?.textColor = .black
header.textLabel?.font = UIFont(name: "Helvetica-Bold", size: 19)
}

Related

How to display multiple attributes in a single table view? Swift

I want to display three different entitys from core data on a table view. I can do this with one entity and tried to carry that logic over to displaying three on the same table view. I used the same entity in the code below to test this. I am getting blank sections in my table view. I must have the cellForRowAt method wrong? Here is my code.
var word: [NSManagedObject] = []
let sections = ["Custom Library", "Mastered Words", "Library"]
var array = [
[NSManagedObject](),
[NSManagedObject](),
[NSManagedObject]()
]
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell2")
array = [
word,
word,
word
]}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array[section].count
}
func numberOfSections(in tableView: UITableView) -> Int {
sections.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sections[section]
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let customWord = array[indexPath.row][indexPath.section]
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell2", for: indexPath)
cell.textLabel?.text = customWord.value(forKeyPath: "title") as? String
return cell
Based on the code you've shown, your array property is an array of empty arrays as word is an empty array itself. If you're using array to determine the number of rows in each section based on the array at that section index, then you're going to get 0 rows for each section.

Swift: how to hide/show rows in section on `didSelectRowAt indexPath`

Here is a sample I want to achieve. In general I have a dataSource like that an array of [Category]:
public struct Category {
let name: String
let image: UIImage
let id: Int
let subCategories: [SubCategory]
var onCategorySelected: (Int) -> Void
}
public struct SubCategory {
let name: String
let id: Int
var onSubCategorySelected: (Int) -> Void
}
I've started with approach that Category is a section and SubCategory is a row. So in numberOfSections I return category array count and in numberOfRowsInSection I return 1 if category is not selected and subcategory.count + 1 if selected. On cellForRowAt I setup proper cell from a custom class.
And I stuck on tableview delegate method: didSelectRowAt indexPath. How can I collapse or expand rows in specific section. I am trying at the moment:
public override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(indexPath)
if indexPath.section == selectedCategory {
var indexToRemove: [IndexPath] = []
(1...props.categories[selectedCategory].subCategories.count).forEach { idx in
indexToRemove.append(IndexPath(row: idx, section: selectedCategory))
}
tableView.beginUpdates()
tableView.deleteRows(at: indexToRemove, with: .top)
tableView.endUpdates()
}
}
I got a crush because I don't update a data source but it seems that I don't actually need to remove these elements from a data source but only hide if first row in section is not selected and show immediately if selected. Any help or even general approach for displaying such structure is welcomed! Thanks!
I think you'll struggle in this way as category headers are don't have built in handlers for tap events (although you could build them into custom header views) but also when the numberOfRows for a section = 0 the section header isn't shown.
A better approach would be to put all entries in a single tableView section with two types of custom cell: one cell design for the categories and one for the sub-categories. Add a Bool variable to Category called something like expanded to track when a section has been expanded. Create an array that hold an entry for each visible cell using an enum with associated values to show whether its a Category or subCategory. Then in didSelectRowAt for a Category cell you can check the expanded property and then either insert or delete the sub-category cells as required.
The outline of the solution will look something like the below (all typed from memory, so may well have some syntax issues, but it should be enough to get you going)
public struct Category {
let name: String
let image: UIImage
let id: Int
let subCategories: [SubCategory]
var expanded = false
var onCategorySelected: (Int) -> Void
}
class CategoryCell: UITableViewCell {
static let cellID = "CategoryCell"
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
//set up imageViews (main & up/down) and textLabel
}
func configure(with category: Category {
//populate cell fields from category
}
}
class CategoryCell: UITableViewCell {
static let cellID = "SubcategoryCell"
// same things as above
}
Then in the view controller
enum RowType {
case category (Category)
case subcategory (SubCategory)
func toggled() -> RowType {
switch self {
case .subcategory: return self
case .category (let category):
category.expanded.toggle()
return .category(category)
}
}
}
//create an array of rows currently being displayed. Start with just Categories
var visibleRows: [RowType] = ArrayOfCategories.map{RowType.Category($0)}
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(CategoryCell.self, forCellReuseIdentifier: CategoryCell.cellID )
tableView.register(SubCategoryCell.self, forCellReuseIdentifier: SubCategoryCell.cellID)
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return visibleRows.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch visibleRows[indexPath.row]
case .Category (let category):
let cell = tableView.dequeueReusableCell(withIdentifier: CategoryCell.CellID, for: indexPath) as! CategoryCell
cell.configure(with: category)
return cell
case .subCategory (let subCategory):
let cell = tableView.dequeueReusableCell(withIdentifier: SubCategoryCell.CellID, for: indexPath) as! SubCategoryCell
cell.configure(with: subCategory)
return cell
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch visibleRows[indexPath.row] {
case .category(let category):
if category.expanded {
tableView.deleteRows(... //delete the subCategory rows
visibleRows.remove( ... //delete the same rows from visibleRows
} else {
visibleRows.insert( ... //insert the .subcategory rows corresponding to the category struct's [subCategory] array
tableView.insertRows(... //insert the appropriate subCategory rows
}
visibleRows[indexPath.row] = visibleRows[indexPath.row].expanded.toggled()
tableView.reloadRows(at:[indexPath.row], with: .fade)
case .subCategory (let subCategory):
//do anything you want for a click on a subCat row
}
}

How to load tableview dynamically in swift 4

I have used Worm Tab Strip cocoapod to get tabs like android, the name of tabs are from server response, I need n number of view controllers based on the number of tab names.
For testing purpose, I have hardcoded tab names, and for each particular tab name, I have another array of sub names. My question is how do I change the tableview contents so that, I get an exact number of sub names according to the tab names
var tabNames = ["Brands", "Sports","Movies", "Mobile","Games"]
var brandsNames = ["Addidas", "Nike","Puma"]
var sportsName = ["Cricket","Fifa","Hockey","Baseball"]
var moviesName = ["Mission Impossible","Matrix","Avatar","Titanic"]
var mobileNames = ["Nokia","Redmi","Samsung"]
var gameNames = ["FIFA 19","PES 19","WWE 2K19","Max Payne"]
What should i try in
func tableView(_ tableView: UITableView, numberOfRowsInSection
section: Int) -> Int {
// return fruits.count
}
And
func tableView(_ tableView: UITableView, cellForRowAt indexPath:
IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell",
for: indexPath) as! Cell1
//cell.textLabel?.text = fruits[indexPath.row]
return cell
}
I need to get for Brands tab, I need brandsNames as tableview
contents.
The tableview contents must change according to the tab names.
Create a custom struct as data model for example
struct Category {
let name : String
let items : [String]
}
Declare a data source array and an index
var categories = [Category]()
var index = 0
In viewDidLoad populate the data source array and set index of the current index of the UISegmentedControl
categories = [Category(name:"Brands", items: ["Addidas", "Nike","Puma"]),
Category(name:"Sports", items: ["Cricket","Fifa","Hockey","Baseball"]),
Category(name:"Movies", items: ["Mission Impossible","Matrix","Avatar","Titanic"]),
Category(name:"Mobile", items: ["Nokia","Redmi","Samsung"]),
Category(name:"Games", items: ["FIFA 19","PES 19","WWE 2K19","Max Payne"])]
index = // current index of the segmented control
in the IBAction of the segmented control set the index and reload the table view
#IBAction func categorySelection(_ sender: UISegmentedControl) {
index = sender.selectedSegmentIndex
tableView.reloadData()
}
The data source methods are
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return categories[index].items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! Cell1
cell.textLabel?.text = categories[index].items[indexPath.row]
return cell
}
I used this enter link description here as a reference So that I can pass ID of particular tab to tableview in viewcontroller and load that Tablview, So now I can dynamically add new tabs and the corresponding Tablview also changes

How to manage section in UITableView

I'm trying to create an application with sections in my TableView.
But actually, I don't know how to manage sections.
I create sections and it works fine but when I try to add a new row in my section I got a problem.
Example:
I Create a new Item in my first section.
The section name is "Aucun" and the rows label is going to set to "Test 1"
It works!
So, now I want to add something else
The section name is "Produits Laitiers" and the row label is "Test2"
FAIL :( The section is create but the row is not the good one
There is my code for the moment
func numberOfSections(in tableView: UITableView) -> Int {
return arraySection.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return arraySection[section]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numberOfRowsInSection[section]
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customCell")
cell?.textLabel?.text = "\(String(describing: products[indexPath.row]["Name"]!))"
cell?.textLabel?.adjustsFontSizeToFitWidth = true
cell?.textLabel?.font = UIFont(name: "Arial", size: 14)
return cell!
}
numberOfRowsInSection is an array of int where I store the number of products which have to be in this section.
You are getting "Test 1" each time, because you have sections, but you are always trying to get a value by using an index of a row without checking an index of a section:
\(String(describing: products[indexPath.row]["Name"]!))
If all your values for cells are storing in a single array, then you should get a value from an array by using the section number:
\(String(describing: products[indexPath.section]["Name"]!))
But this will work only if each section will have only one row. Otherwise you will have to get the number of section first to detect the section where current row is allocated and then get the number of row.
If you have an array of sections with array of rows for each section, that will look like this:
let arraySection = [ [section #0 values], [section #1 values], ...
]
Then you can get the value for each row by using this:
let value = arraySection[indexPath.section][indexPath.row]
========EDIT===========
But there is a much better way - use objects or structs
struct Row {
var value: String = ""
}
struct Section {
var name: String = ""
var values: [Row] = []
}
So, using this structs, your code will be changed:
//your array of sections will contain objects
let arraySection: [Section] = []
func numberOfSections(in tableView: UITableView) -> Int {
return arraySection.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
//get the name of the section
return arraySection[section].name
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//check the count of rows for each section
return arraySection[section].values.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customCell")
// now we can get the value for current row by checking sections and then rows
cell?.textLabel?.text = arraySection[indexPath.section].values[indexPath.row].value
cell?.textLabel?.adjustsFontSizeToFitWidth = true
cell?.textLabel?.font = UIFont(name: "Arial", size: 14)
return cell!
}
I think the problem is with the products array in the UITableViewDataSource method cellForRowAt. You are accessing the same array element for the first object in each section with
products[indexPath.row]["Name"]!
Probably you need to adjust your model to handle the indexPath.section.
The first thing I going to creates a Section model to keep track of the sections, like the following:
/// Defines a section in data source
struct Section {
// MARK: - Properties
/// The title of the section
let title: String
/// The items in the section
var items: [String]
}
Then I going to use a UITableViewController with an Add right button to insert new section/rows to the UITableView, to add new sections/row I going to use a UIAlertController for the sake of brevity with two UITextField's inside where you need to put the name of the section and the name of the row. At the end should look like the following image:
In case the section already exist is going to add the new row to the section, otherwise, is going to create the new section and row dynamically.
DynamicTableViewController
class DynamicTableViewController: UITableViewController {
// MARK: - Properties
/// The data source for the table view
var dataSource = [Section(title: "Section 1", items: ["Row 1"])]
// MARK: - UIViewController
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return dataSource.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource[section].items.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = dataSource[indexPath.section].items[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return dataSource[section].title
}
#IBAction func didTapAddButton(_ sender: Any) {
presentAlerController()
}
}
extension DynamicTableViewController {
func add(_ sectionName: String?, _ row: String?) {
guard let name = sectionName, let rowName = row,
!name.isEmpty, !rowName.isEmpty else {
return
}
if let index = dataSource.index(where: { $0.title == name }) {
dataSource[index].items.append(rowName)
} else {
dataSource.append(Section(title: name, items: [rowName]))
}
tableView.reloadData()
}
func presentAlerController() {
let alertController = UIAlertController(title: "Add", message: "Add new Section/Row", preferredStyle: .alert)
let addAction = UIAlertAction(title: "Add", style: .default) { [weak self] _ in
let sectionTextField = alertController.textFields![0] as UITextField
let rowTextField = alertController.textFields![1] as UITextField
self?.add(sectionTextField.text, rowTextField.text)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { _ in }
alertController.addTextField { textField in
textField.placeholder = "Add a new section name"
}
alertController.addTextField { textField in
textField.placeholder = "Add a new row"
}
alertController.addAction(addAction)
alertController.addAction(cancelAction)
present(alertController, animated: true, completion: nil)
}
}
In the above example, I'm not checking for the existence of duplicate row, you can do it is very easy. Also, I'm using the reloadData(), but you can use too if you want :
// insert the new section with row of the row in the existent section
tableView.beginUpdates()
// insert new section in case of any
insertSections(_ sections: IndexSet, with animation: UITableViewRowAnimation)
// insert new row in section using:
// insertRows(at: [IndexPath], with: UITableViewRowAnimation)
tableView.endUpdates()
Also you need to create a new UIBarButtonItem and connect it to the #IBAction I create it to be able to present the UIAlertController and add new section/row to the UITableView.
I hope this helps you.

swift 2 how to remove empty rows in a tableview in a viewcontroller

Is there a way to reset tableview height so that no empty rows are showed. For an example, a tableview displays 3 rows but there is only one row having real data. I'd like the tableview shrinks it size so there is only one row display
I guess you have a View Controller like this
class Controller: UITableViewController {
private var data: [String?] = ["One", nil, "Three", nil, nil]
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MyCellID")!
cell.textLabel?.text = data[indexPath.row]
return cell
}
}
Since your model (data in my example) contains nil values you are getting a table view like this
One
_
Three
_
_
Removing the empty rows
Now you want instead a table view like this right?
One
Three
Filtering your model
Since the UI (the table view) is just a representation of your model you need to change your model.
It's pretty easy
class Controller: UITableViewController {
private var data: [String?] = ["One", nil, "Three", nil, nil]
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MyCellID")!
cell.textLabel?.text = data[indexPath.row]
return cell
}
override func viewDidLoad() {
data = data.filter { $0 != nil }
super.viewDidLoad()
}
}
As you can see, inside viewDidLoad() I removed the bill values from the data array. Now you'll get only cells for real values.
I think you need remove the empty data before execute func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int.
//EDITED
I give you this possible solution, maybe there are more ways to do it, you can try with this.
class MyViewController: UITableViewDataSource, UITableViewDelegate {
private var realHeight = 0
private var data : [String] = []
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MyCellID")!
cell.textLabel?.text = data[indexPath.row]
self.realHeight += self.tableView.rowHeight //Increase real height value.
return cell
}
func loadData() { //This function reload the data
self.realHeight = 0
self.tableView.reloadData()
//Update tableViewHeight here, use self.realHeight. You can use constraints or update directly the frame.
}
}
The solution is have a counter that represents the sum of all visibles rows height. e.g If you have n cells then your height will be self.tableView.rowHeight * n, then you ever will have an effective height.
I recommend you to create a constraint for the table height and when the cells change, you only need change the constant of the constraint, is more easy than change the frame.